Compare commits

..
17 Commits
Author SHA1 Message Date
heavyrian2012 cfcd8fc276 更新版本号和release note 2026-06-13 10:18:18 +08:00
heavyrian2012 457f417a52 同步专业版server sdk添加获取用户未读数接口 2026-06-13 10:13:19 +08:00
heavyrian2012 b2536992b6 优化文件上传的认证 2026-06-08 12:07:38 +08:00
heavyrian2012 c7102d5dc3 解决serverapi获取频道列表缺少字段的问题 2026-06-05 15:29:25 +08:00
heavyrian2012 fd0ee5c674 添加配置支持机器人和频道应用不校验host 2026-05-18 20:22:31 +08:00
heavyrian2012 af85b08f94 添加会议总结消息 2026-05-18 15:53:17 +08:00
heavyrian2012 de89b44b21 release note and version 2026-05-10 15:12:17 +08:00
heavyrian2012 44b18a66c0 优化批量添加频道订阅功能 2026-05-10 14:55:55 +08:00
heavyrian2012 42281c3ad3 添加部分频道相关server api 2026-05-10 14:30:59 +08:00
heavyrian2012 776c9e26c6 机器人API添加根据邮箱获取用户信息和批量获取用户信息的接口 2026-04-29 15:31:59 +08:00
heavyrian2012 c7f7ce949e 机器人和频道api,请求错误时,result应该为空 2026-04-26 09:42:22 +08:00
heavyrian2012 07b1de4ae3 添加注释 2026-04-20 08:19:38 +08:00
heavyrian2012 7e87f9d6ab 机器人更新消息内容添加distribute接口 2026-04-19 20:06:53 +08:00
heavyrian2012 da781180a7 解决业务系统不限制手机号码重复时,根据手机号码获取用户列表的问题 2026-04-10 21:53:24 +08:00
heavyrian2012 f1b62ad64a 同步专业版数据库 2026-04-10 21:41:49 +08:00
heavyrian2012 576fcf3e77 添加获取所有机器人的接口 2026-04-05 11:28:46 +08:00
heavyrian2012 33f2124352 同步专业版IM服务SDK 2026-03-31 15:57:29 +08:00
50 changed files with 2654 additions and 69 deletions
+114
View File
@@ -0,0 +1,114 @@
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Scanner;
/**
* 此工具为验证IM服务管理密钥是否正确的工具。
* 通过手机号查询 Wildfire IM 用户信息,如果能够返回正确信息或者未找到表示密钥正确。
*
* 编译:放到IM服务运行服务器上,执行 javac VerifyAdminSecretTool.java 编译得到 VerifyAdminSecretTool.class,
* 用法:执行 java VerifyAdminSecretTool 按提示输入 IM 服务地址、管理员密钥、电话号码。
* 程序会调用 /admin/user/get_info 接口并打印返回的 JSON。
*/
public class VerifyAdminSecretTool {
private static final SecureRandom RANDOM = new SecureRandom();
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入 IM 服务地址(如 http://192.168.1.100:18080): ");
String serverUrl = scanner.nextLine().trim();
System.out.print("请输入管理员密钥(admin secret): ");
String secret = scanner.nextLine().trim();
System.out.print("请输入电话号码: ");
String mobile = scanner.nextLine().trim();
scanner.close();
if (serverUrl.isEmpty() || secret.isEmpty() || mobile.isEmpty()) {
System.err.println("错误:服务地址、密钥和电话号码均不能为空");
System.exit(1);
}
// 构建请求 URL(去掉末尾可能的 /)
if (serverUrl.endsWith("/")) {
serverUrl = serverUrl.substring(0, serverUrl.length() - 1);
}
String urlStr = serverUrl + "/admin/user/get_info";
// 构建请求体
String jsonBody = "{\"mobile\":\"" + mobile + "\",\"includeDeleted\":false}";
// 生成认证签名
int nonce = RANDOM.nextInt(1000000) + 1;
long timestamp = System.currentTimeMillis();
String signStr = nonce + "|" + secret + "|" + timestamp;
String sign = sha1Hex(signStr);
// 发送 HTTP POST 请求
String response = doPost(urlStr, jsonBody, nonce, timestamp, sign);
// 输出结果
System.out.println("\n===== 返回结果 =====");
System.out.println(response);
}
private static String doPost(String urlStr, String body, int nonce, long timestamp, String sign) throws Exception {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
try {
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("nonce", String.valueOf(nonce));
conn.setRequestProperty("timestamp", String.valueOf(timestamp));
conn.setRequestProperty("sign", sign);
conn.setDoOutput(true);
conn.setConnectTimeout(15000);
conn.setReadTimeout(15000);
// 写入请求体
try (OutputStream os = conn.getOutputStream()) {
os.write(body.getBytes(StandardCharsets.UTF_8));
os.flush();
}
int responseCode = conn.getResponseCode();
// 读取响应
InputStream is = (responseCode >= 200 && responseCode < 300)
? conn.getInputStream()
: conn.getErrorStream();
StringBuilder sb = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
}
return sb.toString();
} finally {
conn.disconnect();
}
}
private static String sha1Hex(String input) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
}
}
+6
View File
@@ -180,6 +180,9 @@ robot.mention_external_robot true
## 比如允许获取name和email就是5(1+4),允许获取name和mobile和company和type就是531(1+2+16+512),允许全部是1023(1+2+...+512)
#robot.get_user_info_mask 1023
## 机器人应用authToken允许任意host。当为false时,机器人Web应用的host必须和机器人的callback host一致,这样能够增加安全性。
#robot.application_allow_any_host true
## 频道回调信息是否带上用户clientId和平台类型。
channel.callback_with_client_info false
@@ -193,6 +196,9 @@ channel.callback_with_target_info false
## 旧的方式是,automatic为0时,订阅者的消息发给owner,不转发消息到callback地址。为1时,把订阅者的消息转发给callback地址,不发给owner。
channel.new_callback_feature true
## 频道应用authToken允许任意host。当为false时,频道Web应用的host必须和频道的callback host一致,这样能够增加安全性。
#channel.application_allow_any_host true
##禁止搜索用户
friend.disable_search false
+3
View File
@@ -0,0 +1,3 @@
ALTER TABLE `t_conference` ADD COLUMN `_delete_by` varchar(64) DEFAULT '';
ALTER TABLE `t_conference` ADD COLUMN `_deleted` tinyint DEFAULT 0;
ALTER TABLE `t_conference` ADD COLUMN `_delete_dt` bigint(20) DEFAULT 0;
+3
View File
@@ -0,0 +1,3 @@
ALTER TABLE `t_conference` ADD COLUMN `_delete_by` varchar(64) DEFAULT '';
ALTER TABLE `t_conference` ADD COLUMN `_deleted` tinyint DEFAULT 0;
ALTER TABLE `t_conference` ADD COLUMN `_delete_dt` bigint(20) DEFAULT 0;
+1 -1
View File
@@ -5,7 +5,7 @@
<relativePath>../</relativePath>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.4.6</version>
<version>1.4.8</version>
</parent>
<artifactId>moquette-broker</artifactId>
@@ -144,7 +144,7 @@ abstract public class Action {
errorCode = ErrorCode.ERROR_CODE_SUCCESS;
}
RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), RestResult.resultOf(errorCode));
RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), null);
response.setContent(gson.toJson(result));
response.send();
}
@@ -44,8 +44,8 @@ public class UploadFileAction extends Action {
}
public static String getToken(int type) {
String signKey = KEY + "|" + (System.currentTimeMillis()) + "|" + type;
public static String getToken(int type, String key) {
String signKey = KEY + "|" + (System.currentTimeMillis()) + "|" + type + "|" + key;
try {
return DES.encryptDES(signKey);
} catch (Exception e) {
@@ -55,14 +55,17 @@ public class UploadFileAction extends Action {
return null;
}
public static int validateToken(String token) throws InvalidateTokenExecption {
public static int validateToken(String token, String[] fileNames) throws InvalidateTokenExecption {
try {
String signKey = DES.decryptDES(token);
String[] parts = signKey.split("\\|");
if(parts.length == 3) {
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) {
if(parts.length == 4) {
fileNames[0] = parts[3];
}
return Integer.parseInt(parts[2]);
}
}
@@ -153,11 +156,14 @@ public class UploadFileAction extends Action {
try {
int[] bucket = new int[1];
bucket[0] = -1;
String[] fileNames = new String[1];
fileNames[0] = null;
while (decoder.hasNext()) {
InterfaceHttpData data = decoder.next();
if (data != null) {
try {
if(!writeFileUploadData(data, response, requestId, isKeepAlive, bucket)) {
if(!writeFileUploadData(data, response, requestId, isKeepAlive, bucket, fileNames)) {
break;
}
} finally {
@@ -173,12 +179,15 @@ public class UploadFileAction extends Action {
/**
* writeFileUploadData
*/
private boolean writeFileUploadData(InterfaceHttpData data, Response response, String requestId, boolean isKeepAlive, int[] bucket) {
private boolean writeFileUploadData(InterfaceHttpData data, Response response, String requestId, boolean isKeepAlive, int[] bucket, String[] fileNames) {
try {
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
FileUpload fileUpload = (FileUpload) data;
String remoteFileName = fileUpload.getFilename();
if(fileNames[0] != null) {
remoteFileName = fileNames[0];
}
long remoteFileSize = fileUpload.length();
if(bucket[0] == -1) {
@@ -323,7 +332,7 @@ public class UploadFileAction extends Action {
String token = attribute.getValue();
try {
bucket[0] = validateToken(token);
bucket[0] = validateToken(token, fileNames);
} catch (InvalidateTokenExecption e) {
logger.error("无效的token!", e);
response.setStatus(HttpResponseStatus.BAD_REQUEST);
@@ -0,0 +1,41 @@
package com.xiaoleilu.loServer.action.admin;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputSubscribeChannelBatch;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import com.hazelcast.util.StringUtil;
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;
import java.util.concurrent.Executor;
@Route(APIPath.Batch_Subscribe_Channel)
@HttpMethod("POST")
public class ChannelSubscriberBatchAction extends AdminAction {
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
InputSubscribeChannelBatch input = getRequestBody(request.getNettyRequest(), InputSubscribeChannelBatch.class);
if (input != null && !StringUtil.isNullOrEmpty(input.getChannelId()) && input.getUserIds() != null && !input.getUserIds().isEmpty() ) {
ErrorCode errorCode = messagesStore.batchListenChannel(input.getChannelId(), input.getUserIds(), input.getSubscribe()>0);
sendResponse(response, errorCode, null);
} else {
response.setStatus(HttpResponseStatus.OK);
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
response.setContent(gson.toJson(result));
}
}
return true;
}
}
@@ -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.action.admin;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.*;
import cn.wildfirechat.proto.WFCMessage;
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.util.internal.StringUtil;
import java.util.*;
@Route(APIPath.User_Get_All_Robots)
@HttpMethod("POST")
public class GetAllRobotAction extends AdminAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
InputGetUserList input = getRequestBody(request.getNettyRequest(), InputGetUserList.class);
if (input != null && input.count > 0 && input.offset >= 0) {
List<WFCMessage.Robot> robots = messagesStore.getRobotInfoList(input.count, input.offset);
OutputGetRobotList outputGetUserList = new OutputGetRobotList();
outputGetUserList.robotInfoList = new ArrayList<>();
robots.forEach(robotData -> {
WFCMessage.User userInfoData = messagesStore.getUserInfo(robotData.getUid());
if (userInfoData != null && !StringUtil.isNullOrEmpty(userInfoData.getName()) && userInfoData.getDeleted() ==0) {
OutputRobot outputRobot = new OutputRobot();
outputRobot.fromUser(userInfoData);
outputRobot.fromRobot(robotData, true);
outputGetUserList.robotInfoList.add(outputRobot);
}
});
RestResult result = RestResult.ok(outputGetUserList);
setResponseContent(result, response);
} else {
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
}
}
return true;
}
}
@@ -0,0 +1,65 @@
/*
* 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.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.PojoGroupInfo;
import cn.wildfirechat.pojos.PojoGroupInfoList;
import cn.wildfirechat.proto.WFCMessage;
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;
import java.util.ArrayList;
import java.util.List;
@Route(APIPath.Group_Batch_Info)
@HttpMethod("POST")
public class GetBatchGroupInfoAction extends AdminAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
List<String> inputGetGroup = getRequestBody(request.getNettyRequest(), ArrayList.class);
if (inputGetGroup != null && !inputGetGroup.isEmpty()) {
List<WFCMessage.UserRequest> requests = new ArrayList<>();
for (String s : inputGetGroup) {
requests.add(WFCMessage.UserRequest.newBuilder().setUid(s).build());
}
List<WFCMessage.GroupInfo> groupInfoDataList = messagesStore.getGroupInfos(requests);
PojoGroupInfoList pojoGroupInfoList = new PojoGroupInfoList();
pojoGroupInfoList.groupInfoList = new ArrayList<>();
for (WFCMessage.GroupInfo groupInfo : groupInfoDataList) {
pojoGroupInfoList.groupInfoList.add(PojoGroupInfo.fromProto(groupInfo));
}
response.setStatus(HttpResponseStatus.OK);
RestResult result = RestResult.ok(pojoGroupInfoList);
response.setContent(gson.toJson(result));
} else {
response.setStatus(HttpResponseStatus.OK);
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
response.setContent(gson.toJson(result));
}
}
return true;
}
}
@@ -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.action.admin;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputCountOffset;
import cn.wildfirechat.pojos.OutputChannelInfoList;
import cn.wildfirechat.pojos.OutputGetChannelInfo;
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 io.netty.handler.codec.http.FullHttpRequest;
import io.netty.util.internal.StringUtil;
import java.util.ArrayList;
import java.util.List;
@Route(APIPath.List_Channel_Info)
@HttpMethod("POST")
public class GetChannelListAction extends AdminAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
InputCountOffset inputCreateChannel = getRequestBody(request.getNettyRequest(), InputCountOffset.class);
if (inputCreateChannel != null
&& inputCreateChannel.count > 0 && inputCreateChannel.offset >= 0) {
int count = messagesStore.getChannelTotalCount(false);
List<WFCMessage.ChannelInfo> list = messagesStore.getChannelInfoList(inputCreateChannel.count, inputCreateChannel.offset, false);
OutputChannelInfoList outputChannelInfoList = new OutputChannelInfoList();
outputChannelInfoList.total = count;
outputChannelInfoList.list = new ArrayList<>();
for (WFCMessage.ChannelInfo channelData : list) {
outputChannelInfoList.list.add(OutputGetChannelInfo.fromPbInfo(channelData));
}
sendResponse(response, ErrorCode.ERROR_CODE_SUCCESS, outputChannelInfoList);
} else {
sendResponse(response, ErrorCode.INVALID_PARAMETER, null);
}
}
return true;
}
}
@@ -46,25 +46,7 @@ public class GetGroupInfoAction extends AdminAction {
if (groupInfo == null) {
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
} else {
PojoGroupInfo pojoGroupInfo = new PojoGroupInfo();
pojoGroupInfo.setExtra(groupInfo.getExtra());
pojoGroupInfo.setName(groupInfo.getName());
pojoGroupInfo.setOwner(groupInfo.getOwner());
pojoGroupInfo.setPortrait(groupInfo.getPortrait());
pojoGroupInfo.setTarget_id(groupInfo.getTargetId());
pojoGroupInfo.setType(groupInfo.getType());
pojoGroupInfo.setMember_count(groupInfo.getMemberCount());
pojoGroupInfo.setMute(groupInfo.getMute());
pojoGroupInfo.setJoin_type(groupInfo.getJoinType());
pojoGroupInfo.setPrivate_chat(groupInfo.getPrivateChat());
pojoGroupInfo.setSearchable(groupInfo.getSearchable());
pojoGroupInfo.setMax_member_count(groupInfo.getMemberCount());
pojoGroupInfo.setHistory_message(groupInfo.getHistoryMessage());
pojoGroupInfo.setSuper_group(groupInfo.getSuperGroup()>0);
pojoGroupInfo.setDeleted(groupInfo.getDeleted()>0);
pojoGroupInfo.setUpdate_dt(groupInfo.getUpdateDt());
pojoGroupInfo.setMember_update_dt(groupInfo.getMemberUpdateDt());
result = RestResult.ok(pojoGroupInfo);
result = RestResult.ok(PojoGroupInfo.fromProto(groupInfo));
}
setResponseContent(result, response);
} else {
@@ -0,0 +1,65 @@
/*
* 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.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputGetUserInfo;
import cn.wildfirechat.pojos.InputOutputUserInfo;
import cn.wildfirechat.pojos.OutputUserInfoList;
import cn.wildfirechat.proto.WFCMessage;
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.util.internal.StringUtil;
import java.util.ArrayList;
import java.util.List;
@Route(APIPath.User_Get_By_Mobile)
@HttpMethod("POST")
public class GetUsersByMobileAction extends AdminAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
InputGetUserInfo email = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);
if (!StringUtil.isNullOrEmpty(email.getMobile())) {
List<WFCMessage.User> users = messagesStore.getUserInfosByMobile(email.getMobile(), email.isIncludeDeleted());
List<InputOutputUserInfo> list = new ArrayList<>();
for (WFCMessage.User user : users) {
list.add(InputOutputUserInfo.fromPbUser(user));
}
RestResult result;
if (list.isEmpty()) {
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
} else {
OutputUserInfoList outputUserInfoList = new OutputUserInfoList();
outputUserInfoList.userInfos = list;
result = RestResult.ok(outputUserInfoList);
}
setResponseContent(result, response);
} else {
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
}
}
return true;
}
}
@@ -0,0 +1,49 @@
package com.xiaoleilu.loServer.action.admin;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputStringCountOffset;
import cn.wildfirechat.pojos.InputSubscribeChannel;
import cn.wildfirechat.pojos.OutputBooleanValue;
import cn.wildfirechat.pojos.PojoTotalList;
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;
import io.netty.util.internal.StringUtil;
import java.util.List;
@Route(APIPath.List_Channel_Subscriber)
@HttpMethod("POST")
public class ListChannelSubscriberAction extends AdminAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
InputStringCountOffset inputSubscribeChannel = getRequestBody(request.getNettyRequest(), InputStringCountOffset.class);
response.setStatus(HttpResponseStatus.OK);
if (inputSubscribeChannel != null
&& !StringUtil.isNullOrEmpty(inputSubscribeChannel.target)
&& inputSubscribeChannel.count > 0) {
int count = messagesStore.getChannelListenerCount(inputSubscribeChannel.target);
List<String> list = messagesStore.getChannelListenerList(inputSubscribeChannel.target, inputSubscribeChannel.count, inputSubscribeChannel.offset);
RestResult result = RestResult.ok(new PojoTotalList(count, list));
response.setContent(gson.toJson(result));
} else {
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
response.setContent(gson.toJson(result));
}
}
return true;
}
}
@@ -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 cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputChatroomMute;
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;
import io.netty.util.internal.StringUtil;
@Route(APIPath.Chatroom_MuteAll)
@HttpMethod("POST")
public class SetChatroomMuteAction extends AdminAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
InputChatroomMute input = getRequestBody(request.getNettyRequest(), InputChatroomMute.class);
if (input != null
&& !StringUtil.isNullOrEmpty(input.getChatroomId())) {
ErrorCode code = messagesStore.setChatroomState(input.getChatroomId(), input.getStatus());
response.setStatus(HttpResponseStatus.OK);
response.setContent(gson.toJson(RestResult.resultOf(code)));
sendResponse(response, ErrorCode.ERROR_CODE_SUCCESS, null);
} else {
response.setStatus(HttpResponseStatus.OK);
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
response.setContent(gson.toJson(result));
}
}
return true;
}
}
@@ -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.action.admin;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.UserSettingPojo;
import cn.wildfirechat.proto.WFCMessage;
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;
import io.netty.util.internal.StringUtil;
@Route(APIPath.User_Get_Setting)
@HttpMethod("POST")
public class UserSettingGetAction extends AdminAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
UserSettingPojo input = getRequestBody(request.getNettyRequest(), UserSettingPojo.class);
if (input != null && (!StringUtil.isNullOrEmpty(input.getUserId()))) {
WFCMessage.UserSettingEntry entry = messagesStore.getUserSetting(input.getUserId(), input.getScope(), input.getKey());
response.setStatus(HttpResponseStatus.OK);
RestResult result;
if (entry == null) {
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
} else {
input.setValue(entry.getValue());
result = RestResult.ok(input);
}
response.setContent(gson.toJson(result));
} else {
response.setStatus(HttpResponseStatus.OK);
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
response.setContent(gson.toJson(result));
}
}
return true;
}
}
@@ -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.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.UserSettingPojo;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
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.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 static win.liyufan.im.IMTopic.PutUserSettingTopic;
import static win.liyufan.im.UserSettingScope.kUserSettingMyChannels;
@Route(APIPath.User_Put_Setting)
@HttpMethod("POST")
public class UserSettingPutAction extends AdminAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
UserSettingPojo userSettingPojo = getRequestBody(request.getNettyRequest(), UserSettingPojo.class);
if (userSettingPojo != null && !StringUtil.isNullOrEmpty(userSettingPojo.getUserId())) {
WFCMessage.ModifyUserSettingReq modifyUserSettingReq = WFCMessage.ModifyUserSettingReq.newBuilder().setScope(userSettingPojo.getScope()).setKey(userSettingPojo.getKey()).setValue(userSettingPojo.getValue()).build();
sendApiMessage(response, userSettingPojo.getUserId(), PutUserSettingTopic, modifyUserSettingReq.toByteArray(), result -> {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(result);
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
return new Result(errorCode);
});
return false;
} else {
response.setStatus(HttpResponseStatus.OK);
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
response.setContent(gson.toJson(result));
}
}
return true;
}
}
@@ -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.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputOutputUserInfo;
import cn.wildfirechat.pojos.InputStringList;
import cn.wildfirechat.pojos.OutputUserInfoList;
import cn.wildfirechat.proto.WFCMessage;
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.util.internal.StringUtil;
import java.util.ArrayList;
import java.util.List;
@Route(APIPath.Robot_User_Batch_Get_Infos)
@HttpMethod("POST")
public class GetBatchUserAction extends RobotAction {
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
InputStringList inputUserId = getRequestBody(request.getNettyRequest(), InputStringList.class);
if (inputUserId != null && inputUserId.getList() != null && !inputUserId.getList().isEmpty()) {
OutputUserInfoList res = new OutputUserInfoList();
res.userInfos = new ArrayList<>();
int mask = messagesStore.getRobotGetUserInfoMask();
for (String userId : inputUserId.getList()) {
WFCMessage.User user = messagesStore.getUserInfo(userId);
if(user == null || StringUtil.isNullOrEmpty(user.getName())) {
continue;
}
InputOutputUserInfo inputOutputUserInfo = InputOutputUserInfo.fromPbUser(user);
if((mask & 1) == 0) {
inputOutputUserInfo.setName(null);
}
if((mask & 2) == 0) {
inputOutputUserInfo.setMobile(null);
}
if((mask & 4) == 0) {
inputOutputUserInfo.setEmail(null);
}
if((mask & 8) == 0) {
inputOutputUserInfo.setAddress(null);
}
if((mask & 16) == 0) {
inputOutputUserInfo.setCompany(null);
}
if((mask & 32) == 0) {
inputOutputUserInfo.setExtra(null);
}
if((mask & 64) == 0) {
inputOutputUserInfo.setUpdateDt(0);
}
if((mask & 128) == 0) {
inputOutputUserInfo.setGender(0);
}
if((mask & 256) == 0) {
inputOutputUserInfo.setSocial(null);
}
if((mask & 512) == 0) {
inputOutputUserInfo.setType(0);
}
res.userInfos.add(inputOutputUserInfo);
}
RestResult result = RestResult.ok(res);
setResponseContent(result, response);
} else {
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
}
}
return true;
}
}
@@ -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.robot;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputOutputUserInfo;
import cn.wildfirechat.pojos.OutputUserInfoList;
import cn.wildfirechat.proto.WFCMessage;
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.util.internal.StringUtil;
import java.util.ArrayList;
import java.util.List;
@Route(APIPath.Robot_User_Get_Email_Info)
@HttpMethod("POST")
public class GetUsersByEmailAction extends RobotAction {
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
String email = getRequestBody(request.getNettyRequest(), String.class);
if (!StringUtil.isNullOrEmpty(email)) {
List<WFCMessage.User> users = messagesStore.getUserInfosByEmail(email);
List<InputOutputUserInfo> list = new ArrayList<>();
int mask = messagesStore.getRobotGetUserInfoMask();
for (WFCMessage.User user : users) {
InputOutputUserInfo outputUserInfo = InputOutputUserInfo.fromPbUser(user);
if((mask & 1) == 0) {
outputUserInfo.setName(null);
}
if((mask & 2) == 0) {
outputUserInfo.setMobile(null);
}
if((mask & 4) == 0) {
outputUserInfo.setEmail(null);
}
if((mask & 8) == 0) {
outputUserInfo.setAddress(null);
}
if((mask & 16) == 0) {
outputUserInfo.setCompany(null);
}
if((mask & 32) == 0) {
outputUserInfo.setExtra(null);
}
if((mask & 64) == 0) {
outputUserInfo.setUpdateDt(0);
}
if((mask & 128) == 0) {
outputUserInfo.setGender(0);
}
if((mask & 256) == 0) {
outputUserInfo.setSocial(null);
}
if((mask & 512) == 0) {
outputUserInfo.setType(0);
}
list.add(outputUserInfo);
}
RestResult result;
if (list.isEmpty()) {
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
} else {
OutputUserInfoList outputUserInfoList = new OutputUserInfoList();
outputUserInfoList.userInfos = list;
result = RestResult.ok(outputUserInfoList);
}
setResponseContent(result, response);
} else {
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
}
}
return true;
}
}
@@ -186,12 +186,13 @@ public final class BrokerConstants {
public static final String ROBOT_Callback_With_Target_Info = "robot.callback_with_target_info";
public static final String ROBOT_Mention_External_Robot = "robot.mention_external_robot";
public static final String ROBOT_Get_User_Info_Mask = "robot.get_user_info_mask";
public static final String ROBOT_App_Allow_Any_Host = "robot.application_allow_any_host";
public static final String CHANNEL_Callback_With_Client_Info = "channel.callback_with_client_info";
public static final String CHANNEL_Callback_With_Sender_Info = "channel.callback_with_sender_info";
public static final String CHANNEL_Callback_With_Target_Info = "channel.callback_with_target_info";
public static final String CHANNEL_New_Callback_Feature = "channel.new_callback_feature";
public static final String CHANNEL_App_Allow_Any_Host = "channel.application_allow_any_host";
public static final String FRIEND_Disable_Search = "friend.disable_search";
public static final String FRIEND_Disable_NickName_Search = "friend.disable_nick_name_search";
@@ -18,16 +18,28 @@ import io.moquette.server.config.MediaServerConfig;
import io.moquette.spi.impl.Qos1PublishHandler;
import io.netty.buffer.ByteBuf;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import static io.moquette.server.config.MediaServerConfig.FILE_STROAGE_REMOTE_SERVER_URL;
@Handler("GMUT")
public class GetMediaUploadTokenHandler extends IMHandler<WFCMessage.GetUploadTokenRequest> {
@Override
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.GetUploadTokenRequest request, Qos1PublishHandler.IMCallback callback) {
String fileKey = request.getMediaPath();
if(fileKey.contains("/")) {
fileKey = fileKey.substring(fileKey.lastIndexOf("/")+1);
}
String encodedUserId = Base64.getEncoder().encodeToString(fromUser.getBytes(StandardCharsets.UTF_8)).replace("+", "-2B").replace("/", "-2F").replace("=", "-3D");
if(!fileKey.startsWith(fromUser) && !fileKey.startsWith(encodedUserId)) {
LOG.error("GetMediaUploadTokenHandler error: {}, {}", fromUser, request.getMediaPath());
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
int type = request.getMediaType();
String token;
WFCMessage.GetUploadTokenResult.Builder resultBuilder = WFCMessage.GetUploadTokenResult.newBuilder();
if (MediaServerConfig.USER_QINIU) {
Auth auth = Auth.create(MediaServerConfig.QINIU_ACCESS_KEY, MediaServerConfig.QINIU_SECRET_KEY);
@@ -93,12 +105,12 @@ public class GetMediaUploadTokenHandler extends IMHandler<WFCMessage.GetUploadTo
break;
}
token = auth.uploadToken(bucketName);
token = auth.uploadToken(bucketName, request.getMediaPath());
resultBuilder.setDomain(bucketDomain)
.setServer(MediaServerConfig.QINIU_SERVER_URL);
resultBuilder.setPort(80);
} else {
token = UploadFileAction.getToken(type);
token = UploadFileAction.getToken(type, request.getMediaPath());
if(StringUtil.isNullOrEmpty(MediaServerConfig.FILE_STROAGE_REMOTE_SERVER_URL)) {
resultBuilder.setDomain("http://" + MediaServerConfig.SERVER_IP + ":" + MediaServerConfig.HTTP_SERVER_PORT);
} else {
@@ -104,7 +104,7 @@ public class GetQiniuUploadTokenHandler extends IMHandler<Byte> {
.setServer(MediaServerConfig.QINIU_SERVER_URL);
resultBuilder.setPort(80);
} else {
token = UploadFileAction.getToken(type);
token = UploadFileAction.getToken(type, null);
resultBuilder.setDomain("http://" + MediaServerConfig.SERVER_IP + ":" + MediaServerConfig.HTTP_SERVER_PORT)
.setServer(MediaServerConfig.SERVER_IP);
resultBuilder.setPort(MediaServerConfig.HTTP_SERVER_PORT);
@@ -3091,6 +3091,102 @@ public class DatabaseStore {
return outList;
}
List<WFCMessage.User> getUserInfosByMobile(String mobile, boolean includeDeleted) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
List<WFCMessage.User> outList = new ArrayList<>();
try {
connection = DBUtil.getConnection();
String sql = "select `_uid`, `_name`" +
", `_display_name`" +
", `_portrait`" +
", `_mobile`" +
", `_gender`" +
", `_email`" +
", `_address`" +
", `_company`" +
", `_social`" +
", `_extra`" +
", `_type`" +
", `_deleted`" +
", `_dt` from t_user where `_mobile` = ?";
if(!includeDeleted) {
sql += " and `_deleted` = 0";
}
statement = connection.prepareStatement(sql);
statement.setString(1, mobile);
rs = statement.executeQuery();
while (rs.next()) {
WFCMessage.User.Builder builder = WFCMessage.User.newBuilder();
int index = 1;
String value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setUid(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setName(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setDisplayName(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setPortrait(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setMobile(value);
int gender = rs.getInt(index++);
builder.setGender(gender);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setEmail(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setAddress(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setCompany(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setSocial(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setExtra(value);
int type = rs.getInt(index++);
builder.setType(type);
int deleted = rs.getInt(index++);
builder.setDeleted(deleted);
long longValue = rs.getLong(index++);
if(longValue <= 0)
longValue = 1;
builder.setUpdateDt(longValue);
outList.add(builder.build());
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e, RDBS_Exception);
} finally {
DBUtil.closeDB(connection, statement, rs);
}
return outList;
}
List<WFCMessage.User> getAllUsers(int count, int offset) {
Connection connection = null;
PreparedStatement statement = null;
@@ -3188,6 +3284,69 @@ public class DatabaseStore {
return outList;
}
List<WFCMessage.Robot> getAllRobots(int count, int offset) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
List<WFCMessage.Robot> outList = new ArrayList<>();
try {
connection = DBUtil.getConnection();
String sql = "select `_uid`, `_owner`" +
", `_secret`" +
", `_callback`" +
", `_state`" +
", `_extra`" +
", `_dt` from t_robot limit ? offset ?";
statement = connection.prepareStatement(sql);
int index = 1;
statement.setInt(1, count);
statement.setInt(2, offset);
rs = statement.executeQuery();
while (rs.next()) {
WFCMessage.Robot.Builder builder = WFCMessage.Robot.newBuilder();
index = 1;
String value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setUid(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setOwner(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setSecret(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setCallback(value);
int state = rs.getInt(index++);
builder.setState(state);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setExtra(value);
long longValue = rs.getLong(index++);
outList.add(builder.build());
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e, RDBS_Exception);
} finally {
DBUtil.closeDB(connection, statement, rs);
}
return outList;
}
List<String> getUserRobotIds(String userId) {
Connection connection = null;
PreparedStatement statement = null;
@@ -3758,7 +3917,6 @@ public class DatabaseStore {
return null;
}
void persistChannelListener(final String groupId, final List<String> memberList) {
mScheduler.execute(()->{
Connection connection = null;
@@ -4023,6 +4181,313 @@ public class DatabaseStore {
}
}
void batchInsertChannelListener(String channelId, List<String> listeners, boolean listen) throws SQLException {
LOG.info("updateChannelListener {}", channelId);
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
int size = 0;
String sql = listen
? "insert into t_channel_listener (_cid, _mid, _dt) values(?, ?, ?)"
: "delete from t_channel_listener where _cid=? and _mid=?";
statement = connection.prepareStatement(sql);
for (String listener : listeners) {
int index = 1;
statement.setString(index++, channelId);
statement.setString(index++, listener);
if (listen) {
statement.setLong(index++, System.currentTimeMillis());
}
statement.addBatch();
if(++size%100 == 0) {
statement.executeBatch();
statement.clearBatch();
}
}
if(size%100 != 0) {
statement.executeBatch();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e, RDBS_Exception);
throw e;
} finally {
DBUtil.closeDB(connection, statement);
}
}
public List<String> findMissingMids(String cid, List<String> midList, boolean contain) {
if (midList == null || midList.isEmpty()) {
return new ArrayList<>();
}
String tempTable = "temp_check_mids_" + System.currentTimeMillis();
Connection conn = null;
try {
conn = DBUtil.getConnection();
// Step 1: 创建临时表
try (Statement st = conn.createStatement()) {
st.execute("CREATE TEMPORARY TABLE " + tempTable +
" (_mid VARCHAR(64) NOT NULL PRIMARY KEY)");
}
// Step 2: 批量插入
String insertSql = "INSERT IGNORE INTO " + tempTable + " (_mid) VALUES (?)";
try (PreparedStatement ps = conn.prepareStatement(insertSql)) {
int count = 0;
for (String mid : midList) {
ps.setString(1, mid);
ps.addBatch();
if (++count % 1000 == 0) {
ps.executeBatch();
ps.clearBatch();
}
}
if (count % 1000 != 0) {
ps.executeBatch();
}
}
// Step 3: 查询
String querySql = "SELECT t._mid FROM " + tempTable + " t " +
"WHERE " + (contain ? "" : " NOT ") + " EXISTS (" +
" SELECT 1 FROM t_channel_listener c " +
" WHERE c._cid = ? AND c._mid = t._mid" +
")";
List<String> result = new ArrayList<>();
try (PreparedStatement ps = conn.prepareStatement(querySql)) {
ps.setString(1, cid);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
result.add(rs.getString(1));
}
}
}
return result;
} catch (SQLException e) {
throw new RuntimeException("查询缺失mid失败", e);
} finally {
// 显式清理临时表
if (conn != null) {
try (Statement st = conn.createStatement()) {
st.execute("DROP TEMPORARY TABLE IF EXISTS " + tempTable);
} catch (SQLException ignored) {
// 清理失败不影响主流程
} finally {
try { conn.close(); } catch (SQLException ignored) {}
}
}
}
}
List<WFCMessage.ChannelInfo> getChannelInfoList(int count, int offset, boolean withDeleted) {
List<WFCMessage.ChannelInfo> out = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
connection = DBUtil.getConnection();
String sql = "select _cid, _name" +
", _portrait" +
", _owner" +
", _secret" +
", _status" +
", _desc" +
", _extra" +
", _callback" +
", _automatic" +
", _menu" +
", _dt from t_channel";
if(!withDeleted) {
sql += " where _status <> 64 ";
}
sql += " order by _dt desc ";
sql += " limit " + count;
if (offset > 0) {
sql += " offset " + offset;
}
statement = connection.prepareStatement(sql);
rs = statement.executeQuery();
while (rs.next()) {
WFCMessage.ChannelInfo.Builder builder = WFCMessage.ChannelInfo.newBuilder();
int index = 1;
String value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setTargetId(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setName(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setPortrait(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setOwner(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setSecret(value);
int status = rs.getInt(index++);
builder.setStatus(status);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setDesc(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setExtra(value);
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setCallback(value);
int intValue = rs.getInt(index++);
builder.setAutomatic(intValue);
try {
byte[] bytes = null;
Blob blob = rs.getBlob(index++);
if (blob != null) {
bytes = toByteArray(blob.getBinaryStream());
}
if (bytes != null) {
WFCMessage.ChannelMenuList menuButtonList = WFCMessage.ChannelMenuList.parseFrom(bytes);
if (menuButtonList.getMenuCount() > 0) {
for (int i = 0; i < menuButtonList.getMenuCount(); i++) {
builder.addMenu(menuButtonList.getMenu(i));
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
long longValue = rs.getLong(index++);
builder.setUpdateDt(longValue);
out.add(builder.build());
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e, RDBS_Exception);
} finally {
DBUtil.closeDB(connection, statement, rs);
}
return out;
}
int getChannelTotalCount(boolean withDeleted) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
connection = DBUtil.getConnection();
String sql = "select count(*) from t_channel";
if(!withDeleted) {
sql += " where _status <> 64";
}
statement = connection.prepareStatement(sql);
rs = statement.executeQuery();
if (rs.next()) {
return rs.getInt(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e, RDBS_Exception);
} finally {
DBUtil.closeDB(connection, statement, rs);
}
return 0;
}
public int getChannelListenerCount(String channelId) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
connection = DBUtil.getConnection();
String sql = "select count(*) from t_channel_listener where _cid = ?";
statement = connection.prepareStatement(sql);
int index = 1;
statement.setString(index++, channelId);
rs = statement.executeQuery();
if (rs.next()) {
return rs.getInt(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e, RDBS_Exception);
} finally {
DBUtil.closeDB(connection, statement, rs);
}
return 0;
}
public List<String> getChannelListenerList(String channelId, int count, int offset) {
List<String> out = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
connection = DBUtil.getConnection();
String sql = "select _mid from t_channel_listener where _cid = ?";
if(count > 0) {
sql += " limit " + count;
}
if(offset > 0) {
sql += " offset " + offset;
}
statement = connection.prepareStatement(sql);
int index = 1;
statement.setString(index++, channelId);
rs = statement.executeQuery();
while (rs.next()) {
String value = rs.getString(1);
if (!StringUtil.isNullOrEmpty(value)) {
out.add(value);
}
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e, RDBS_Exception);
} finally {
DBUtil.closeDB(connection, statement, rs);
}
return out;
}
public Set<String> getSensitiveWord() {
Connection connection = null;
PreparedStatement statement = null;
@@ -48,6 +48,7 @@ import win.liyufan.im.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -78,6 +79,7 @@ import static io.moquette.BrokerConstants.*;
import static io.moquette.server.Constants.MAX_CHATROOM_MESSAGE_QUEUE;
import static io.moquette.server.Constants.MAX_MESSAGE_QUEUE;
import static cn.wildfirechat.pojos.MyInfoType.*;
import static win.liyufan.im.IMTopic.PutUserSettingTopic;
import static win.liyufan.im.UserSettingScope.*;
public class MemoryMessagesStore implements IMessagesStore {
@@ -222,11 +224,13 @@ public class MemoryMessagesStore implements IMessagesStore {
private boolean mRobotCallbackWithTargetInfo = false;
private boolean mRobotMentionExternalRobot = false;
private int mRobotGetUserInfoMask = 0;
private boolean mRobotAppAllowAnyHost = false;
private boolean mChannelCallbackWithClientInfo = false;
private boolean mChannelCallbackWithSenderInfo = false;
private boolean mChannelCallbackWithTargetInfo = false;
private boolean mChannelNewCallbackFeature = true;
private boolean mChannelAppAllowAnyHost = false;
private Set<Integer> mUserHideProperties = new HashSet<>();
@@ -687,6 +691,9 @@ public class MemoryMessagesStore implements IMessagesStore {
try {
mRobotGetUserInfoMask = Integer.parseInt(server.getConfig().getProperty(BrokerConstants.ROBOT_Get_User_Info_Mask, "0"));
} catch (Exception e) {}
try {
mRobotAppAllowAnyHost = "true".equalsIgnoreCase(server.getConfig().getProperty(BrokerConstants.ROBOT_App_Allow_Any_Host, "false"));
} catch (Exception e) {}
try {
mChannelCallbackWithClientInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_Callback_With_Client_Info, "false"));
@@ -697,10 +704,12 @@ public class MemoryMessagesStore implements IMessagesStore {
try {
mChannelCallbackWithTargetInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_Callback_With_Target_Info, "false"));
} catch (Exception e) {}
try {
mChannelNewCallbackFeature = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_New_Callback_Feature, "true"));
} catch (Exception e) {}
try {
mChannelAppAllowAnyHost = "true".equalsIgnoreCase(server.getConfig().getProperty(BrokerConstants.CHANNEL_App_Allow_Any_Host, "false"));
} catch (Exception e) {}
try {
mRecallForwardUrl = server.getConfig().getProperty(BrokerConstants.MESSAGE_RecallMsg_Forward_Url);
@@ -1341,6 +1350,20 @@ public class MemoryMessagesStore implements IMessagesStore {
return false;
}
@Override
public ErrorCode setChatroomState(String chatroomId, int status) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
IMap<String, WFCMessage.ChatroomInfo> chatroomInfoMap = hzInstance.getMap(CHATROOMS);
WFCMessage.ChatroomInfo info = chatroomInfoMap.get(chatroomId);
if (info == null) {
return ErrorCode.ERROR_CODE_NOT_EXIST;
}
info = info.toBuilder().setState(status).build();
chatroomInfoMap.set(chatroomId, info);
return ErrorCode.ERROR_CODE_SUCCESS;
}
@Override
public long insertChatroomMessages(String target, int line, long messageId) {
// messageId是全局的,messageSeq是跟个人相关的,理论上messageId的增长数度远远大于seq。
@@ -2325,6 +2348,19 @@ public class MemoryMessagesStore implements IMessagesStore {
return out;
}
@Override
public List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);
ArrayList<WFCMessage.GroupInfo> out = new ArrayList<>();
for (WFCMessage.UserRequest request : requests) {
WFCMessage.GroupInfo groupInfo = mIMap.get(request.getUid());
out.add(groupInfo);
}
return out;
}
@Override
public WFCMessage.GroupInfo getGroupInfo(String groupId) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
@@ -3272,11 +3308,21 @@ public class MemoryMessagesStore implements IMessagesStore {
return databaseStore.getUserInfosByEmail(email);
}
@Override
public List<WFCMessage.User> getUserInfosByMobile(String mobile, boolean includeDeleted) {
return databaseStore.getUserInfosByMobile(mobile, includeDeleted);
}
@Override
public List<WFCMessage.User> getUserInfoList(int count, int offset) {
return databaseStore.getAllUsers(count, offset);
}
@Override
public List<WFCMessage.Robot> getRobotInfoList(int count, int offset) {
return databaseStore.getAllRobots(count, offset);
}
@Override
public List<String> getUserRobotIds(String userId) {
return databaseStore.getUserRobotIds(userId);
@@ -4177,12 +4223,12 @@ public class MemoryMessagesStore implements IMessagesStore {
String secret = null;
if(type == ProtoConstants.ApplicationType.ApplicationType_Robot) {
WFCMessage.Robot robotData = getRobot(applicationId);
if(robotData != null && !StringUtil.isNullOrEmpty(robotData.getCallback()) && !StringUtil.isNullOrEmpty(robotData.getSecret())) {
if(robotData != null && (mRobotAppAllowAnyHost || !StringUtil.isNullOrEmpty(robotData.getCallback())) && !StringUtil.isNullOrEmpty(robotData.getSecret())) {
try {
URL url = new URL(robotData.getCallback());
if(url.getHost() == null) {
LOG.error("get application auth code error, application callback is invalid url");
} else if(url.getHost().equals(host)) {
} else if(mRobotAppAllowAnyHost || url.getHost().equals(host)) {
secret = robotData.getSecret();
} else {
LOG.error("get application auth code error, request host is not the same host with callback host");
@@ -4203,12 +4249,12 @@ public class MemoryMessagesStore implements IMessagesStore {
}
} else if(type == ProtoConstants.ApplicationType.ApplicationType_Channel) {
WFCMessage.ChannelInfo channelData = getChannelInfo(applicationId);
if(channelData != null && !StringUtil.isNullOrEmpty(channelData.getCallback()) && !StringUtil.isNullOrEmpty(channelData.getSecret())) {
if(channelData != null && (mChannelAppAllowAnyHost || !StringUtil.isNullOrEmpty(channelData.getCallback())) && !StringUtil.isNullOrEmpty(channelData.getSecret())) {
try {
URL url = new URL(channelData.getCallback());
if(url.getHost() == null) {
LOG.error("get application auth code error, application callback is invalid url");
} else if(url.getHost().equals(host)) {
} else if(mChannelAppAllowAnyHost || url.getHost().equals(host)) {
secret = channelData.getSecret();
} else {
LOG.error("get application auth code error, request host is not the same host with callback host");
@@ -4246,12 +4292,12 @@ public class MemoryMessagesStore implements IMessagesStore {
String secret = null;
if(type == ProtoConstants.ApplicationType.ApplicationType_Robot) {
WFCMessage.Robot robotData = getRobot(applicationId);
if(robotData != null && !StringUtil.isNullOrEmpty(robotData.getCallback()) && !StringUtil.isNullOrEmpty(robotData.getSecret())) {
if(robotData != null && (mRobotAppAllowAnyHost || !StringUtil.isNullOrEmpty(robotData.getCallback())) && !StringUtil.isNullOrEmpty(robotData.getSecret())) {
secret = robotData.getSecret();
}
} else if(type == ProtoConstants.ApplicationType.ApplicationType_Channel) {
WFCMessage.ChannelInfo channelData = getChannelInfo(applicationId);
if(channelData != null && !StringUtil.isNullOrEmpty(channelData.getCallback()) && !StringUtil.isNullOrEmpty(channelData.getSecret())) {
if(channelData != null && (mChannelAppAllowAnyHost || !StringUtil.isNullOrEmpty(channelData.getCallback())) && !StringUtil.isNullOrEmpty(channelData.getSecret())) {
secret = channelData.getSecret();
}
} else if(type == ProtoConstants.ApplicationType.ApplicationType_Admin) {
@@ -4915,6 +4961,56 @@ public class MemoryMessagesStore implements IMessagesStore {
return getChannelListener(channelId);
}
@Override
public List<WFCMessage.ChannelInfo> getChannelInfoList(int count, int offset, boolean withDeleted) {
return databaseStore.getChannelInfoList(count, offset, withDeleted);
}
@Override
public int getChannelTotalCount(boolean withDeleted) {
return databaseStore.getChannelTotalCount(withDeleted);
}
@Override
public ErrorCode batchListenChannel(String channelId, List<String> userIds, boolean listen) {
IMap<String, WFCMessage.ChannelInfo> mIMap = m_Server.getHazelcastInstance().getMap(CHANNELS);
WFCMessage.ChannelInfo channelData = mIMap.get(channelId);
if(channelData == null || (channelData.getStatus() & Channel_State_Mask_Deleted) > 0) {
return ErrorCode.ERROR_CODE_NOT_EXIST;
}
List<String> missedIds = databaseStore.findMissingMids(channelId, userIds, !listen);
try {
databaseStore.batchInsertChannelListener(channelId, missedIds, listen);
} catch (SQLException e) {
throw new RuntimeException(e);
}
new Thread(() -> {
for (String missedId : missedIds) {
WFCMessage.ModifyUserSettingReq modifyUserSettingReq = WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingListenedChannels).setKey(channelId).setValue(listen? "1" : "0").build();
m_Server.onApiMessage(missedId, null, modifyUserSettingReq.toByteArray(), 0, missedId, PutUserSettingTopic, ProtoConstants.RequestSourceType.Request_From_User);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
return ErrorCode.ERROR_CODE_SUCCESS;
}
@Override
public int getChannelListenerCount(String channelId) {
return databaseStore.getChannelListenerCount(channelId);
}
@Override
public List<String> getChannelListenerList(String channelId, int count, int offset) {
return databaseStore.getChannelListenerList(channelId, count, offset);
}
@Override
public int getOnlineUserCount() {
return m_Server.getProcessor().getConnectionDescriptors().getActiveConnectionsNo();
@@ -113,6 +113,7 @@ public interface IMessagesStore {
ErrorCode modifyGroupMemberAlias(String operator, String groupId, String alias, String memberId, boolean isAdmin);
ErrorCode modifyGroupMemberExtra(String operator, String groupId, String extra, String memberId, boolean isAdmin);
List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests, String fromUser, boolean isAdmin);
List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests);
WFCMessage.GroupInfo getGroupInfo(String groupId);
Set<String> getUserGroupIds(String userId);
Set<String> getUserGroupIds(String userId, List<Integer> types);
@@ -154,9 +155,11 @@ public interface IMessagesStore {
WFCMessage.User getUserInfoByName(String name);
WFCMessage.User getUserInfoByMobile(String mobile);
List<WFCMessage.User> getUserInfosByEmail(String email);
List<WFCMessage.User> getUserInfosByMobile(String mobile, boolean includeDeleted);
ErrorCode searchUser(String userId, String keyword, int searchType, int userType, int page, List<WFCMessage.User> users);
List<WFCMessage.User> getUserInfoList(int count, int offset);
List<WFCMessage.Robot> getRobotInfoList(int count, int offset);
List<String> getUserRobotIds(String userId);
boolean updateSystemSetting(int id, String value, String desc);
@@ -168,6 +171,7 @@ public interface IMessagesStore {
int getChatroomMemberCount(String chatroomId);
Collection<String> getChatroomMemberClient(String userId);
boolean checkUserClientInChatroom(String user, String clientId, String chatroomId);
ErrorCode setChatroomState(String chatroomId, int status);
long insertChatroomMessages(String target, int line, long messageId);
Collection<UserClientEntry> getChatroomMembers(String chatroomId);
@@ -230,6 +234,12 @@ public interface IMessagesStore {
boolean canSendMessageInChannel(String user, String channelId);
boolean checkUserInChannel(String user, String channelId);
Collection<String> getChannelSubscriber(String channelId);
List<WFCMessage.ChannelInfo> getChannelInfoList(int count, int offset, boolean withDeleted);
int getChannelTotalCount(boolean withDeleted);
ErrorCode batchListenChannel(String channelId, List<String> userIds, boolean listen);
int getChannelListenerCount(String channelId);
List<String> getChannelListenerList(String channelId, int count, int offset);
int getOnlineUserCount();
GetOnlineUserResult getOnlineUsers(int offset, int count);
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.4.6</version>
<version>1.4.8</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -43,8 +43,10 @@ public interface APIPath {
String User_Get_Info = "/admin/user/get_info";
String User_Batch_Get_Infos = "/admin/user/batch_get_infos";
String User_Get_Email_Info = "/admin/user/get_info_by_email";
String User_Get_By_Mobile = "/admin/user/get_info_by_mobile";
String User_Get_All = "/admin/user/all";
String User_Get_Robot_Info = "/admin/user/get_robot_info";
String User_Get_All_Robots = "/admin/user/get_all_robots";
String User_Get_User_Robots = "/admin/user/get_user_robots";
String User_Get_Blocked_List = "/admin/user/get_blocked_list";
String User_Check_Block_Status = "/admin/user/check_block_status";
@@ -55,6 +57,7 @@ public interface APIPath {
String User_Online_Count = "/admin/user/online_count";
String User_Online_List = "/admin/user/online_list";
String User_Session_List = "/admin/user/session_list";
String User_Unread_count = "/admin/user/unread_count";
String User_Application_Get_UserInfo = "/admin/user/app_get_user_info";
String Friend_Update_Status = "/admin/friend/status";
@@ -88,6 +91,7 @@ public interface APIPath {
String Msg_Delivery = "/admin/message/delivery";
String Conversation_Delete = "/admin/conversation/delete";
String Msg_Clear_By_User = "/admin/message/clear_by_user";
String Msg_Import = "/admin/message/import";
String Create_Group = "/admin/group/create";
String Group_Dismiss = "/admin/group/del";
@@ -117,8 +121,11 @@ public interface APIPath {
String Create_Channel = "/admin/channel/create";
String Destroy_Channel = "/admin/channel/destroy";
String Get_Channel_Info = "/admin/channel/get";
String List_Channel_Info = "/admin/channel/list";
String Subscribe_Channel = "/admin/channel/subscribe";
String Batch_Subscribe_Channel = "/admin/channel/batch_subscribe";
String Check_User_Subscribe_Channel = "/admin/channel/is_subscribed";
String List_Channel_Subscriber = "/admin/channel/list_subscriber";
String Get_System_Setting = "/admin/system/get_setting";
String Put_System_Setting = "/admin/system/put_setting";
String GET_CUSTOMER = "/admin/customer";
@@ -151,6 +158,8 @@ public interface APIPath {
String Channel_Application_Get_UserInfo = "/channel/application/get_user_info";
String Robot_User_Info = "/robot/user_info";
String Robot_User_Get_Email_Info = "/robot/user/get_info_by_email";
String Robot_User_Batch_Get_Infos = "/robot/user/batch_get_infos";
String Robot_Get_Profile = "/robot/profile";
String Robot_Message_Send = "/robot/message/send";
String Robot_Message_Reply = "/robot/message/reply";
@@ -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 cn.wildfirechat.pojos;
import cn.wildfirechat.proto.WFCMessage;
import java.util.List;
public class ImportMessagesData {
public static class ImportMessage {
public String sender;
public Conversation conversation;
public MessagePayload payload;
public List<String> receivers;
public long timestamp;
}
public List<ImportMessage> messages;
}
@@ -0,0 +1,16 @@
package cn.wildfirechat.pojos;
public class InputStringCountOffset {
public String target;
public int count;
public int offset;
public InputStringCountOffset() {
}
public InputStringCountOffset(String target, int count, int offset) {
this.target = target;
this.count = count;
this.offset = offset;
}
}
@@ -0,0 +1,50 @@
/*
* 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 cn.wildfirechat.pojos;
import java.util.List;
public class InputSubscribeChannelBatch {
private String channelId;
private List<String> userIds;
private int subscribe; //1,订阅;0,取消订阅
public InputSubscribeChannelBatch() {
}
public InputSubscribeChannelBatch(String channelId, List<String> userIds, int subscribe) {
this.channelId = channelId;
this.userIds = userIds;
this.subscribe = subscribe;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public List<String> getUserIds() {
return userIds;
}
public void setUserIds(List<String> userIds) {
this.userIds = userIds;
}
public int getSubscribe() {
return subscribe;
}
public void setSubscribe(int subscribe) {
this.subscribe = subscribe;
}
}
@@ -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 cn.wildfirechat.pojos;
import cn.wildfirechat.proto.WFCMessage;
import java.util.ArrayList;
import java.util.List;
public class OutputChannelInfoList {
public List<OutputGetChannelInfo> list;
public int total;
}
@@ -0,0 +1,7 @@
package cn.wildfirechat.pojos;
import java.util.List;
public class OutputGetRobotList {
public List<OutputRobot> robotInfoList;
}
@@ -0,0 +1,11 @@
package cn.wildfirechat.pojos;
import java.util.ArrayList;
import java.util.List;
public class OutputUserUnreadCount {
public int unreceivedMessageCount;
public int uploadedUnreadCount;
}
@@ -8,6 +8,8 @@
package cn.wildfirechat.pojos;
import cn.wildfirechat.proto.WFCMessage;
/**
* 群组信息类
* <p>
@@ -175,4 +177,26 @@ public class PojoGroupInfo {
public void setMember_update_dt(long member_update_dt) {
this.member_update_dt = member_update_dt;
}
static public PojoGroupInfo fromProto(WFCMessage.GroupInfo groupInfo) {
PojoGroupInfo pojoGroupInfo = new PojoGroupInfo();
pojoGroupInfo.setExtra(groupInfo.getExtra());
pojoGroupInfo.setName(groupInfo.getName());
pojoGroupInfo.setOwner(groupInfo.getOwner());
pojoGroupInfo.setPortrait(groupInfo.getPortrait());
pojoGroupInfo.setTarget_id(groupInfo.getTargetId());
pojoGroupInfo.setType(groupInfo.getType());
pojoGroupInfo.setMember_count(groupInfo.getMemberCount());
pojoGroupInfo.setMute(groupInfo.getMute());
pojoGroupInfo.setJoin_type(groupInfo.getJoinType());
pojoGroupInfo.setPrivate_chat(groupInfo.getPrivateChat());
pojoGroupInfo.setSearchable(groupInfo.getSearchable());
pojoGroupInfo.setMax_member_count(groupInfo.getMemberCount());
pojoGroupInfo.setHistory_message(groupInfo.getHistoryMessage());
pojoGroupInfo.setSuper_group(groupInfo.getSuperGroup()>0);
pojoGroupInfo.setDeleted(groupInfo.getDeleted()>0);
pojoGroupInfo.setUpdate_dt(groupInfo.getUpdateDt());
pojoGroupInfo.setMember_update_dt(groupInfo.getMemberUpdateDt());
return pojoGroupInfo;
}
}
@@ -0,0 +1,16 @@
package cn.wildfirechat.pojos;
import java.util.List;
public class PojoTotalList {
public int total;
public List<String> list;
public PojoTotalList() {
}
public PojoTotalList(int total, List<String> list) {
this.total = total;
this.list = list;
}
}
@@ -107,6 +107,8 @@ public class ProtoConstants {
int StreamingText_Generationg = 14;
int StreamingText_Generated = 15;
int Not_Delivered = 16;
int Meeting_Minutes = 25;
int Transcription = 26;
int Ptt_Voice = 23;
int Enter_Channel_Chat = 71;
int Leave_Channel_Chat = 72;
+1 -1
View File
@@ -6,7 +6,7 @@
<!--<relativePath>../pom.xml</relativePath>-->
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.4.6</version>
<version>1.4.8</version>
</parent>
<artifactId>distribution</artifactId>
@@ -177,6 +177,9 @@ robot.mention_external_robot true
## 比如允许获取name和email就是5(1+4),允许获取name和mobile和company和type就是531(1+2+16+512),允许全部是1023(1+2+...+512)
#robot.get_user_info_mask 1023
## 机器人应用authToken允许任意host。当为false时,机器人Web应用的host必须和机器人的callback host一致,这样能够增加安全性。
#robot.application_allow_any_host true
## 频道回调信息是否带上用户clientId和平台类型。
channel.callback_with_client_info false
@@ -190,6 +193,9 @@ channel.callback_with_target_info false
## 旧的方式是,automatic为0时,订阅者的消息发给owner,不转发消息到callback地址。为1时,把订阅者的消息转发给callback地址,不发给owner。
channel.new_callback_feature true
## 频道应用authToken允许任意host。当为false时,频道Web应用的host必须和频道的callback host一致,这样能够增加安全性。
#channel.application_allow_any_host true
##禁止搜索用户
friend.disable_search false
+1 -1
View File
@@ -12,7 +12,7 @@
<artifactId>wildfirechat-parent</artifactId>
<packaging>pom</packaging>
<version>1.4.6</version>
<version>1.4.8</version>
<name>Wildfire Chat</name>
<description>Wildfire Chat Server</description>
<inceptionYear>2019</inceptionYear>
+16
View File
@@ -12,6 +12,22 @@
11. *** 1.3.8版本添加了server api发送消息的限制,限制消息体最大内容不能超过64KB,如果升级请注意业务系统发送消息大小。***
# 更新记录
--------------
Release note 1.4.8:
1. 添加配置支持机器人和频道应用不校验host。
2. 解决server api获取频道列表缺少字段。
3. 优化文件上传认证的问题。
4. 同步专业版IM服务SDK添加获取未读数接口。
Release note 1.4.7:
1. 添加获取所有机器人的Server API接口。
2. 添加获取某个电话号码的用户列表的Server API接口。
3. 机器人发送消息distribute为false时不重新分发。
4. 解决机器人和频道API请求错误时result不为空的问题。
5. 机器人添加根据邮箱获取用户信息和批量获取用户信息的接口。
6. 添加批量订阅/取消订阅的频道接口,添加批量获取订阅用户的接口。
--------------
Release note 1.4.6:
1. 添加网盘存储类型。
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.4.6</version>
<version>1.4.8</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -2,9 +2,12 @@ package cn.wildfirechat.sdk;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.pojos.*;
import cn.wildfirechat.pojos.mesh.PojoStringList;
import cn.wildfirechat.sdk.model.IMResult;
import cn.wildfirechat.sdk.utilities.AdminHttpUtils;
import java.util.List;
/**
* 频道管理类
* <p>
@@ -53,6 +56,21 @@ public class ChannelAdmin {
return AdminHttpUtils.httpJsonPost(path, inputChannelId, OutputGetChannelInfo.class);
}
/**
* 获取频道信息列表
* @param count 数量
* @param offset offset
* @return 频道信息列表
* @throws Exception 请求失败时抛出异常
*/
public static IMResult<OutputChannelInfoList> getChannelInfoList(int count, int offset) throws Exception {
String path = APIPath.List_Channel_Info;
InputCountOffset inputCountOffset = new InputCountOffset();
inputCountOffset.count = count;
inputCountOffset.offset = offset;
return AdminHttpUtils.httpJsonPost(path, inputCountOffset, OutputChannelInfoList.class);
}
/**
* 订阅频道
* @param channelId 频道ID
@@ -66,6 +84,19 @@ public class ChannelAdmin {
return AdminHttpUtils.httpJsonPost(path, input, Void.class);
}
/**
* 批量用户订阅频道
* @param channelId 频道ID
* @param userIds 用户ID列表
* @return 订阅结果
* @throws Exception 请求失败时抛出异常
*/
public static IMResult<Void> batchSubscribeChannel(String channelId, List<String> userIds) throws Exception {
String path = APIPath.Batch_Subscribe_Channel;
InputSubscribeChannelBatch input = new InputSubscribeChannelBatch(channelId, userIds, 1);
return AdminHttpUtils.httpJsonPost(path, input, Void.class);
}
/**
* 取消订阅频道
* @param channelId 频道ID
@@ -79,6 +110,19 @@ public class ChannelAdmin {
return AdminHttpUtils.httpJsonPost(path, input, Void.class);
}
/**
* 批量用户取消订阅频道
* @param channelId 频道ID
* @param userIds 用户ID列表
* @return 取消订阅结果
* @throws Exception 请求失败时抛出异常
*/
public static IMResult<Void> batchUnsubscribeChannel(String channelId, List<String> userIds) throws Exception {
String path = APIPath.Batch_Subscribe_Channel;
InputSubscribeChannelBatch input = new InputSubscribeChannelBatch(channelId, userIds, 0);
return AdminHttpUtils.httpJsonPost(path, input, Void.class);
}
/**
* 检查用户是否订阅了频道
* @param userId 用户ID
@@ -91,4 +135,18 @@ public class ChannelAdmin {
InputSubscribeChannel input = new InputSubscribeChannel(channelId, userId, 0);
return AdminHttpUtils.httpJsonPost(path, input, OutputBooleanValue.class);
}
/**
* 获取频道订阅用户列表
* @param channelId 频道ID
* @param count
* @param offset
* @return 订阅用户id列表
* @throws Exception 请求失败时抛出异常
*/
public static IMResult<PojoTotalList> getChannelSubscribers(String channelId, int count, int offset) throws Exception {
String path = APIPath.List_Channel_Subscriber;
InputStringCountOffset input = new InputStringCountOffset(channelId, count, offset);
return AdminHttpUtils.httpJsonPost(path, input, PojoTotalList.class);
}
}
@@ -41,24 +41,49 @@ public class ChannelServiceApi implements Closeable {
channelHttpUtils = new ChannelHttpUtils(imurl, channelId, secret);
}
/**
* 根据用户ID获取用户信息
* @param userId 用户ID
* @return 用户信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<InputOutputUserInfo> getUserInfo(String userId) throws Exception {
String path = APIPath.Channel_User_Info;
InputGetUserInfo getUserInfo = new InputGetUserInfo(userId, null, null);
return channelHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);
}
/**
* 根据用户名获取用户信息
* @param userName 用户名
* @return 用户信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<InputOutputUserInfo> getUserInfoByName(String userName) throws Exception {
String path = APIPath.Channel_User_Info;
InputGetUserInfo getUserInfo = new InputGetUserInfo(null, userName, null);
return channelHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);
}
/**
* 根据手机号获取用户信息
* @param mobile 手机号
* @return 用户信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<InputOutputUserInfo> getUserInfoByMobile(String mobile) throws Exception {
String path = APIPath.Channel_User_Info;
InputGetUserInfo getUserInfo = new InputGetUserInfo(null, null, mobile);
return channelHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);
}
/**
* 修改频道信息
* @param type 修改类型,参考{@link cn.wildfirechat.proto.ProtoConstants.ModifyChannelInfoType}
* @param value 修改的值
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> modifyChannelInfo(/*ProtoConstants.ModifyChannelInfoType*/int type, String value) throws Exception {
String path = APIPath.Channel_Update_Profile;
InputModifyChannelInfo modifyChannelInfo = new InputModifyChannelInfo();
@@ -67,16 +92,35 @@ public class ChannelServiceApi implements Closeable {
return channelHttpUtils.httpJsonPost(path, modifyChannelInfo, Void.class);
}
/**
* 获取频道信息
* @return 频道信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputGetChannelInfo> getChannelInfo() throws Exception {
String path = APIPath.Channel_Get_Profile;
return channelHttpUtils.httpJsonPost(path, null, OutputGetChannelInfo.class);
}
/**
* 修改频道菜单
* @param menus 菜单列表
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> modifyChannelMenu(List<PojoChannelMenu> menus) throws Exception {
String menuStr = new Gson().toJson(menus);
return modifyChannelInfo(ProtoConstants.ModifyChannelInfoType.Modify_Channel_Menu, menuStr);
}
/**
* 发送频道消息
* @param line 线路
* @param targets 目标用户ID列表
* @param payload 消息内容
* @return 发送结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<SendMessageResult> sendMessage(int line, List<String> targets, MessagePayload payload) throws Exception {
String path = APIPath.Channel_Message_Send;
SendChannelMessageData messageData = new SendChannelMessageData();
@@ -86,6 +130,12 @@ public class ChannelServiceApi implements Closeable {
return channelHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);
}
/**
* 撤回频道消息
* @param messageUid 消息UID
* @return 操作结果,返回被撤回消息的UID
* @throws Exception 请求失败时抛出异常
*/
public IMResult<String> recallMessage(long messageUid) throws Exception {
String path = APIPath.Channel_Msg_Recall;
RecallMessageData messageData = new RecallMessageData();
@@ -93,6 +143,13 @@ public class ChannelServiceApi implements Closeable {
return channelHttpUtils.httpJsonPost(path, messageData, String.class);
}
/**
* 重新发布频道消息
* @param messageUid 消息UID
* @param targets 目标用户ID列表
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> republishMessage(long messageUid, List<String> targets) throws Exception {
String path = APIPath.Channel_Msg_Republish;
RepublishChannelMessageData messageData = new RepublishChannelMessageData();
@@ -101,6 +158,12 @@ public class ChannelServiceApi implements Closeable {
return channelHttpUtils.httpJsonPost(path, messageData, Void.class);
}
/**
* 订阅频道
* @param userId 用户ID
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> subscribe(String userId) throws Exception {
String path = APIPath.Channel_Subscribe;
InputChannelSubscribe input = new InputChannelSubscribe();
@@ -109,6 +172,12 @@ public class ChannelServiceApi implements Closeable {
return channelHttpUtils.httpJsonPost(path, input, Void.class);
}
/**
* 取消订阅频道
* @param userId 用户ID
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> unsubscribe(String userId) throws Exception {
String path = APIPath.Channel_Subscribe;
InputChannelSubscribe input = new InputChannelSubscribe();
@@ -117,17 +186,34 @@ public class ChannelServiceApi implements Closeable {
return channelHttpUtils.httpJsonPost(path, input, Void.class);
}
/**
* 获取频道订阅者列表
* @return 订阅者用户ID列表
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputStringList> getSubscriberList() throws Exception {
String path = APIPath.Channel_Subscriber_List;
return channelHttpUtils.httpJsonPost(path, null, OutputStringList.class);
}
/**
* 判断用户是否订阅了频道
* @param userId 用户ID
* @return 是否订阅
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Boolean> isSubscriber(String userId) throws Exception {
String path = APIPath.Channel_Is_Subscriber;
InputUserId input = new InputUserId(userId);
return channelHttpUtils.httpJsonPost(path, input, Boolean.class);
}
/**
* 通过授权码获取应用用户信息
* @param authCode 授权码
* @return 应用用户信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputApplicationUserInfo> applicationGetUserInfo(String authCode) throws Exception {
String path = APIPath.Channel_Application_Get_UserInfo;
InputApplicationGetUserInfo input = new InputApplicationGetUserInfo();
@@ -135,6 +221,11 @@ public class ChannelServiceApi implements Closeable {
return channelHttpUtils.httpJsonPost(path, input, OutputApplicationUserInfo.class);
}
/**
* 获取应用签名配置
* <p>用于客户端接入时的签名验证</p>
* @return 应用签名配置数据
*/
public OutputApplicationConfigData getApplicationSignature() {
int nonce = (int)(Math.random() * 100000 + 3);
long timestamp = System.currentTimeMillis()/1000;
@@ -149,6 +240,10 @@ public class ChannelServiceApi implements Closeable {
return configData;
}
/**
* 关闭服务,释放资源
* @throws IOException 关闭时发生IO异常
*/
@Override
public void close() throws IOException {
channelHttpUtils.close();
File diff suppressed because one or more lines are too long
@@ -5,6 +5,7 @@ import cn.wildfirechat.pojos.*;
import cn.wildfirechat.sdk.model.IMResult;
import cn.wildfirechat.sdk.utilities.AdminHttpUtils;
import java.util.ArrayList;
import java.util.List;
/**
@@ -293,4 +294,20 @@ public class MessageAdmin {
InputUserId input = new InputUserId(userId);
return AdminHttpUtils.httpJsonPost(path, input, OutputTimestamp.class);
}
/**
* 导入消息。只用在服务为正式使用之前,从别的IM服务进行导入历史消息。当导入时,只能部署一个节点,可以多线程导入。当导入结束后,检查有没有异常日志,如果有异常日志需要解决后重新导入。
* 当导入完成后,重启IM服务(不要用kill -9,需要等待缓存写入)。重启之后再用客户端验证是否有历史消息可以从远端加载。另外需要保留之前IM服务的备份记录,以防有消息泄漏。
* 下面所有参数必须有效才行,如果是群组消息,还需要先创建群组。
*
* @param messages 消息列表
* @return 导入结果
* @throws Exception
*/
public static IMResult<Void> importMessage(List<ImportMessagesData.ImportMessage> messages) throws Exception {
String path = APIPath.Msg_Import;
ImportMessagesData messageData = new ImportMessagesData();
messageData.messages = messages;
return AdminHttpUtils.httpJsonPost(path, messageData, Void.class);
}
}
@@ -97,6 +97,14 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);
}
/**
* 回复消息
* @param messageUid 原消息UID
* @param payload 消息内容
* @param only2Sender 是否只回复给原发送者
* @return 发送结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<SendMessageResult> replyMessage(long messageUid, MessagePayload payload, boolean only2Sender) throws Exception {
String path = APIPath.Robot_Message_Reply;
ReplyMessageData messageData = new ReplyMessageData();
@@ -106,6 +114,12 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);
}
/**
* 撤回消息
* @param messageUid 消息UID
* @return 操作结果,返回被撤回消息的UID
* @throws Exception 请求失败时抛出异常
*/
public IMResult<String> recallMessage(long messageUid) throws Exception {
String path = APIPath.Robot_Message_Recall;
RecallMessageData messageData = new RecallMessageData();
@@ -113,34 +127,101 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, messageData, String.class);
}
/**
* 更新消息内容
* @param messageUid 消息UID
* @param payload 新的消息内容
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> updateMessage(long messageUid, MessagePayload payload) throws Exception {
return updateMessage(messageUid, payload, true);
}
/**
* 更新消息内容
* @param messageUid 消息UID
* @param payload 新的消息内容
* @param distribute 是否分发给在线用户
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> updateMessage(long messageUid, MessagePayload payload, boolean distribute) throws Exception {
String path = APIPath.Robot_Message_Update;
UpdateMessageContentData updateMessageContentData = new UpdateMessageContentData();
updateMessageContentData.setMessageUid(messageUid);
updateMessageContentData.setPayload(payload);
updateMessageContentData.setUpdateTimestamp(0);
updateMessageContentData.setDistribute(1);
updateMessageContentData.setDistribute(distribute?1:0);
return robotHttpUtils.httpJsonPost(path, updateMessageContentData, Void.class);
}
/**
* 根据用户ID获取用户信息
* @param userId 用户ID
* @return 用户信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<InputOutputUserInfo> getUserInfo(String userId) throws Exception {
String path = APIPath.Robot_User_Info;
InputGetUserInfo getUserInfo = new InputGetUserInfo(userId, null, null);
return robotHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);
}
/**
* 根据手机号获取用户信息
* @param phone 手机号
* @return 用户信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<InputOutputUserInfo> getUserInfoByMobile(String phone) throws Exception {
String path = APIPath.Robot_User_Info;
InputGetUserInfo getUserInfo = new InputGetUserInfo(null, null, phone);
return robotHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);
}
/**
* 根据用户名获取用户信息
* @param userName 用户名
* @return 用户信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<InputOutputUserInfo> getUserInfoByName(String userName) throws Exception {
String path = APIPath.Robot_User_Info;
InputGetUserInfo getUserInfo = new InputGetUserInfo(null, userName, null);
return robotHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);
}
/**
* 根据邮箱获取用户信息列表
* @param email 邮箱地址
* @return 用户信息列表
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputUserInfoList> getUserInfoByEmail(String email) throws Exception {
String path = APIPath.Robot_User_Get_Email_Info;
return robotHttpUtils.httpJsonPost(path, email, OutputUserInfoList.class);
}
/**
* 批量获取用户信息
* @param userIds 用户ID列表
* @return 用户信息列表
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputUserInfoList> getBatchUsers(List<String> userIds) throws Exception {
String path = APIPath.Robot_User_Batch_Get_Infos;
InputStringList input = new InputStringList();
input.setList(userIds);
return robotHttpUtils.httpJsonPost(path, input, OutputUserInfoList.class);
}
/**
* 设置机器人消息回调地址
* @param url 回调地址
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> setCallback(String url) throws Exception {
String path = APIPath.Robot_Set_Callback;
RobotCallbackPojo pojo = new RobotCallbackPojo();
@@ -148,23 +229,43 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, pojo, Void.class);
}
/**
* 获取机器人消息回调地址
* @return 回调信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<RobotCallbackPojo> getCallback() throws Exception {
String path = APIPath.Robot_Get_Callback;
return robotHttpUtils.httpJsonPost(path, null, RobotCallbackPojo.class);
}
/**
* 删除机器人消息回调地址
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> deleteCallback() throws Exception {
String path = APIPath.Robot_Delete_Callback;
return robotHttpUtils.httpJsonPost(path, null, Void.class);
}
/**
* 获取机器人资料
* @return 机器人资料
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputRobot> getProfile() throws Exception {
String path = APIPath.Robot_Get_Profile;
return robotHttpUtils.httpJsonPost(path, null, OutputRobot.class);
}
/*
type可选范围为MyInfoType,注意不能修改电话号码,如果要修改电话号码请使用adminapi进行修改
/**
* 更新机器人资料
* <p>type可选范围为MyInfoType,注意不能修改电话号码,如果要修改电话号码请使用adminapi进行修改</p>
* @param type 资料类型,参考MyInfoType
* @param value 资料值
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> updateProfile(int/*MyInfoType*/ type, String value) throws Exception {
String path = APIPath.Robot_Update_Profile;
@@ -172,6 +273,16 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, pojo, Void.class);
}
/**
* 创建群组
* @param group_info 群组信息
* @param members 群成员列表
* @param member_extra 成员扩展信息
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 创建结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputCreateGroupResult> createGroup(PojoGroupInfo group_info, List<PojoGroupMember> members, String member_extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Create_Group;
PojoGroup pojoGroup = new PojoGroup();
@@ -186,6 +297,12 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, createGroup, OutputCreateGroupResult.class);
}
/**
* 获取群组信息
* @param groupId 群组ID
* @return 群组信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<PojoGroupInfo> getGroupInfo(String groupId) throws Exception {
String path = APIPath.Robot_Group_Get_Info;
InputGetGroup input = new InputGetGroup();
@@ -194,6 +311,14 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, input, PojoGroupInfo.class);
}
/**
* 解散群组
* @param groupId 群组ID
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> dismissGroup(String groupId, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Dismiss;
InputDismissGroup dismissGroup = new InputDismissGroup();
@@ -203,6 +328,15 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, dismissGroup, Void.class);
}
/**
* 转让群组
* @param groupId 群组ID
* @param newOwner 新群主用户ID
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> transferGroup(String groupId, String newOwner, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Transfer;
InputTransferGroup transferGroup = new InputTransferGroup();
@@ -213,6 +347,16 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, transferGroup, Void.class);
}
/**
* 修改群组信息
* @param groupId 群组ID
* @param type 修改类型,参考ModifyGroupInfoType
* @param value 修改的值
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> modifyGroupInfo(String groupId, /*ModifyGroupInfoType*/int type, String value, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Modify_Info;
InputModifyGroupInfo modifyGroupInfo = new InputModifyGroupInfo();
@@ -225,6 +369,12 @@ public class RobotService implements Closeable {
}
/**
* 获取群成员列表
* @param groupId 群组ID
* @return 群成员列表
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputGroupMemberList> getGroupMembers(String groupId) throws Exception {
String path = APIPath.Robot_Group_Member_List;
InputGetGroup input = new InputGetGroup();
@@ -232,6 +382,13 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, input, OutputGroupMemberList.class);
}
/**
* 获取指定群成员信息
* @param groupId 群组ID
* @param memberId 成员用户ID
* @return 群成员信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<PojoGroupMember> getGroupMember(String groupId, String memberId) throws Exception {
String path = APIPath.Robot_Group_Member_Get;
InputGetGroupMember input = new InputGetGroupMember();
@@ -240,6 +397,16 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, input, PojoGroupMember.class);
}
/**
* 添加群成员
* @param groupId 群组ID
* @param groupMembers 要添加的成员列表
* @param member_extra 成员扩展信息
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> addGroupMembers(String groupId, List<PojoGroupMember> groupMembers, String member_extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Member_Add;
InputAddGroupMember addGroupMember = new InputAddGroupMember();
@@ -251,6 +418,16 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);
}
/**
* 设置群管理员
* @param groupId 群组ID
* @param groupMemberIds 成员用户ID列表
* @param isManager 是否设为管理员
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> setGroupManager(String groupId, List<String> groupMemberIds, boolean isManager, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Set_Manager;
InputSetGroupManager addGroupMember = new InputSetGroupManager();
@@ -262,6 +439,16 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);
}
/**
* 禁言/取消禁言群成员
* @param groupId 群组ID
* @param groupMemberIds 成员用户ID列表
* @param isMute 是否禁言
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> muteGroupMember(String groupId, List<String> groupMemberIds, boolean isMute, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Mute_Member;
InputMuteGroupMember addGroupMember = new InputMuteGroupMember();
@@ -273,6 +460,16 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);
}
/**
* 允许/禁止群成员
* @param groupId 群组ID
* @param groupMemberIds 成员用户ID列表
* @param isAllow 是否允许
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> allowGroupMember(String groupId, List<String> groupMemberIds, boolean isAllow, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Allow_Member;
InputMuteGroupMember addGroupMember = new InputMuteGroupMember();
@@ -284,6 +481,15 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);
}
/**
* 踢出群成员
* @param groupId 群组ID
* @param groupMemberIds 要踢出的成员用户ID列表
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> kickoffGroupMembers(String groupId, List<String> groupMemberIds, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Member_Kickoff;
InputKickoffGroupMember kickoffGroupMember = new InputKickoffGroupMember();
@@ -294,6 +500,14 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, kickoffGroupMember, Void.class);
}
/**
* 退出群组
* @param groupId 群组ID
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> quitGroup(String groupId, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Member_Quit;
InputQuitGroup quitGroup = new InputQuitGroup();
@@ -303,6 +517,16 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, quitGroup, Void.class);
}
/**
* 设置群成员昵称
* @param groupId 群组ID
* @param memberId 成员用户ID
* @param alias 群昵称
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> setGroupMemberAlias(String groupId, String memberId, String alias, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Set_Member_Alias;
InputSetGroupMemberAlias input = new InputSetGroupMemberAlias();
@@ -314,6 +538,16 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, input, Void.class);
}
/**
* 设置群成员扩展信息
* @param groupId 群组ID
* @param memberId 成员用户ID
* @param extra 扩展信息
* @param to_lines 指定线路
* @param notify_message 通知消息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> setGroupMemberExtra(String groupId, String memberId, String extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
String path = APIPath.Robot_Group_Set_Member_Extra;
InputSetGroupMemberExtra input = new InputSetGroupMemberExtra();
@@ -325,6 +559,12 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, input, Void.class);
}
/**
* 通过授权码获取应用用户信息
* @param authCode 授权码
* @return 应用用户信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputApplicationUserInfo> applicationGetUserInfo(String authCode) throws Exception {
String path = APIPath.Robot_Application_Get_UserInfo;
InputApplicationGetUserInfo input = new InputApplicationGetUserInfo();
@@ -332,6 +572,11 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, input, OutputApplicationUserInfo.class);
}
/**
* 获取应用签名配置
* <p>用于客户端接入时的签名验证</p>
* @return 应用签名配置数据
*/
public OutputApplicationConfigData getApplicationSignature() {
int nonce = (int)(Math.random() * 100000 + 3);
long timestamp = System.currentTimeMillis()/1000;
@@ -346,12 +591,36 @@ public class RobotService implements Closeable {
return configData;
}
/**
* 发送会议相关请求
* @param robotId 机器人ID
* @param clientId 客户端ID
* @param request 请求类型
* @param sessionId 会话ID
* @param roomId 会议室ID
* @param data 请求数据
* @param advance 是否高级请求
* @return 请求结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<String> sendConferenceRequest(String robotId, String clientId, String request, long sessionId, String roomId, String data, boolean advance) throws Exception {
String path = APIPath.Robot_Conference_Request;
InputConferenceRequest input = new InputConferenceRequest(robotId, clientId, request, sessionId, roomId, data, advance);
return robotHttpUtils.httpJsonPost(path, input, String.class);
}
/**
* 发布朋友圈动态
* @param type 内容类型,参考MomentsContentType
* @param text 文本内容
* @param medias 媒体列表
* @param toUsers 可见用户列表
* @param excludeUsers 不可见用户列表
* @param mentionedUsers 提及用户列表
* @param extra 扩展信息
* @return 发布结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<FeedPojo> postMomentsFeed(int/*MomentsContentType*/ type, String text, List<MediaEntry> medias, List<String> toUsers, List<String> excludeUsers, List<String> mentionedUsers, String extra) throws Exception {
String path = APIPath.Robot_Moments_Post_Feed;
FeedPojo feedPojo = new FeedPojo();
@@ -376,6 +645,19 @@ public class RobotService implements Closeable {
return feedResult;
}
/**
* 更新朋友圈动态
* @param feedId 动态ID
* @param type 内容类型,参考MomentsContentType
* @param text 文本内容
* @param medias 媒体列表
* @param toUsers 可见用户列表
* @param excludeUsers 不可见用户列表
* @param mentionedUsers 提及用户列表
* @param extra 扩展信息
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> updateMomentsFeed(long feedId, int/*MomentsContentType*/ type, String text, List<MediaEntry> medias, List<String> toUsers, List<String> excludeUsers, List<String> mentionedUsers, String extra) throws Exception {
String path = APIPath.Robot_Moments_Update_Feed;
FeedPojo feedPojo = new FeedPojo();
@@ -390,6 +672,14 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, feedPojo, Void.class);
}
/**
* 获取朋友圈动态列表
* @param feedId 起始动态ID
* @param count 获取数量
* @param user 指定用户ID,为空表示获取所有
* @return 动态列表
* @throws Exception 请求失败时抛出异常
*/
public IMResult<FeedsPojo> getMomentsFeeds(long feedId, int count, String user) throws Exception {
String path = APIPath.Robot_Moments_Pull_Feeds;
PullFeedRequestPojo requestPojo = new PullFeedRequestPojo();
@@ -399,6 +689,12 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, FeedsPojo.class);
}
/**
* 获取单条朋友圈动态
* @param feedId 动态ID
* @return 动态详情
* @throws Exception 请求失败时抛出异常
*/
public IMResult<FeedPojo> getMomentsFeed(long feedId) throws Exception {
String path = APIPath.Robot_Moments_Fetch_Feed;
PullOneFeedRequestPojo requestPojo = new PullOneFeedRequestPojo();
@@ -406,6 +702,12 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, FeedPojo.class);
}
/**
* 删除朋友圈动态
* @param feedId 动态ID
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> deleteMomentsFeed(long feedId) throws Exception {
String path = APIPath.Robot_Moments_Recall_Feed;
IdPojo requestPojo = new IdPojo();
@@ -413,6 +715,17 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
}
/**
* 发布朋友圈评论
* @param feedId 动态ID
* @param replyId 回复的评论ID
* @param type 评论类型,参考MomentsCommentType
* @param text 评论内容
* @param replyTo 回复目标用户ID
* @param extra 扩展信息
* @return 评论结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<CommentPojo> postMomentsComment(long feedId, long replyId, int/*MomentsCommentType*/ type, String text, String replyTo, String extra) throws Exception {
String path = APIPath.Robot_Moments_Post_Comment;
CommentPojo commentPojo = new CommentPojo();
@@ -436,6 +749,13 @@ public class RobotService implements Closeable {
return feedResult;
}
/**
* 删除朋友圈评论
* @param feedId 动态ID
* @param commentId 评论ID
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> deleteMomentsComment(long feedId, long commentId) throws Exception {
String path = APIPath.Robot_Moments_Recall_Comment;
IdPojo requestPojo = new IdPojo();
@@ -444,6 +764,12 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
}
/**
* 获取用户朋友圈资料
* @param userId 用户ID
* @return 朋友圈资料
* @throws Exception 请求失败时抛出异常
*/
public IMResult<MomentProfilePojo> getUserMomentsProfile(String userId) throws Exception {
String path = APIPath.Robot_Moments_Fetch_Profiles;
PullProfileRequestPojo requestPojo = new PullProfileRequestPojo();
@@ -451,6 +777,12 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, MomentProfilePojo.class);
}
/**
* 更新朋友圈背景图
* @param url 背景图URL
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> updateMomentsBackgroundUrl(String url) throws Exception {
String path = APIPath.Robot_Moments_Update_Profiles_Value;
PushProfileValueRequestPojo requestPojo = new PushProfileValueRequestPojo();
@@ -459,6 +791,12 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
}
/**
* 更新朋友圈陌生人可见数量
* @param count 可见数量
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> updateMomentsStrangerVisibleCount(int count) throws Exception {
String path = APIPath.Robot_Moments_Update_Profiles_Value;
PushProfileValueRequestPojo requestPojo = new PushProfileValueRequestPojo();
@@ -467,6 +805,12 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
}
/**
* 更新朋友圈可见范围
* @param scope 可见范围,参考MomentsVisibleScope
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> updateMomentsVisibleScope(int/*MomentsVisibleScope*/ scope) throws Exception {
String path = APIPath.Robot_Moments_Update_Profiles_Value;
PushProfileValueRequestPojo requestPojo = new PushProfileValueRequestPojo();
@@ -475,6 +819,13 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
}
/**
* 更新朋友圈黑名单
* @param addList 要添加的用户ID列表
* @param removeList 要移除的用户ID列表
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> updateMomentsBlackList(List<String> addList, List<String> removeList) throws Exception {
String path = APIPath.Robot_Moments_Update_Profiles_List_Value;
PushProfileListRequestPojo requestPojo = new PushProfileListRequestPojo();
@@ -484,6 +835,13 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
}
/**
* 更新朋友圈屏蔽列表
* @param addList 要添加的用户ID列表
* @param removeList 要移除的用户ID列表
* @return 操作结果
* @throws Exception 请求失败时抛出异常
*/
public IMResult<Void> updateMomentsBlockList(List<String> addList, List<String> removeList) throws Exception {
String path = APIPath.Robot_Moments_Update_Profiles_List_Value;
PushProfileListRequestPojo requestPojo = new PushProfileListRequestPojo();
@@ -493,6 +851,14 @@ public class RobotService implements Closeable {
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
}
/**
* 获取预签名上传地址
* @param fileName 文件名
* @param mediaType 媒体类型,参考{@link cn.wildfirechat.proto.ProtoConstants.MessageMediaType}
* @param contentType 文件Content-Type
* @return 预签名上传地址信息
* @throws Exception 请求失败时抛出异常
*/
public IMResult<OutputPresignedUploadUrl> getPresignedUploadUrl(String fileName, int/*ProtoConstants.MessageMediaType*/ mediaType, String contentType) throws Exception {
String path = APIPath.Robot_Get_Presigned_Upload_Url;
@@ -820,6 +1186,10 @@ public class RobotService implements Closeable {
// 注意:正常流程下的流关闭在 uploadToQiniu 或 uploadToOther 的 finally 块中处理
}
/**
* 关闭服务,释放资源
* @throws IOException 关闭时发生IO异常
*/
@Override
public void close() throws IOException {
robotHttpUtils.close();
@@ -70,6 +70,7 @@ public class UserAdmin {
/**
* 根据手机号获取用户信息(不包含已删除用户)
* @deprecated 用户手机号码不要求唯一,正常应该业务系统保证电话号码唯一。如果业务系统不限制电话号码唯一,可能一个号码有多个用户,此方法只能返回一个,此时建议使用 {@link #getUsersByMobile(String mobile, boolean includeDeleted)}
* @param mobile 手机号
* @return 用户信息
* @throws Exception 请求失败时抛出异常
@@ -79,7 +80,8 @@ public class UserAdmin {
}
/**
* 根据手机号获取用户信息
* 根据手机号获取用户信息,
* @deprecated 用户手机号码不要求唯一,正常应该业务系统保证电话号码唯一。如果业务系统不限制电话号码唯一,可能一个号码有多个用户,此方法只能返回一个,此时建议使用 {@link #getUsersByMobile(String mobile, boolean includeDeleted)}
* @param mobile 手机号
* @param includeDeleted 是否包含已删除的用户
* @return 用户信息
@@ -91,6 +93,19 @@ public class UserAdmin {
return AdminHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);
}
/**
* 根据电话号码获取用户信息列表
* @param mobile 邮箱地址
* @param includeDeleted 是否包含已删除的用户
* @return 用户信息列表
* @throws Exception 请求失败时抛出异常
*/
public static IMResult<OutputUserInfoList> getUsersByMobile(String mobile, boolean includeDeleted) throws Exception {
String path = APIPath.User_Get_By_Mobile;
InputGetUserInfo getUserInfo = new InputGetUserInfo(null, null, mobile, includeDeleted);
return AdminHttpUtils.httpJsonPost(path, getUserInfo, OutputUserInfoList.class);
}
/**
* 根据邮箱获取用户信息列表
* @param email 邮箱地址
@@ -117,6 +132,21 @@ public class UserAdmin {
return AdminHttpUtils.httpJsonPost(path, input, OutputGetUserList.class);
}
/**
* 获取所有机器人列表(分页)
* @param count 每页数量
* @param offset 偏移量
* @return 机器人列表
* @throws Exception 请求失败时抛出异常
*/
public static IMResult<OutputGetRobotList> getAllRobots(int count, int offset) throws Exception {
String path = APIPath.User_Get_All_Robots;
InputGetUserList input = new InputGetUserList();
input.count = count;
input.offset = offset;
return AdminHttpUtils.httpJsonPost(path, input, OutputGetRobotList.class);
}
/**
* 批量获取用户信息
* @param userIds 用户ID列表
@@ -384,4 +414,15 @@ public class UserAdmin {
InputUserId inputUserId = new InputUserId(userId);
return AdminHttpUtils.httpJsonPost(APIPath.User_Session_List, inputUserId, GetUserSessionResult.class);
}
/**
* 获取用户的未读数,只有专业版IM服务支持,未读数不是很准确,只能表示一个大概。
* @param userId
* @return 用户的未读数,包括未接收消息和客户端上报的未读数。
* @throws Exception
*/
public static IMResult<OutputUserUnreadCount> getUserUnreadCount(String userId) throws Exception {
InputUserId inputUserId = new InputUserId(userId);
return AdminHttpUtils.httpJsonPost(APIPath.User_Unread_count, inputUserId, OutputUserUnreadCount.class);
}
}
@@ -0,0 +1,96 @@
package cn.wildfirechat.sdk.messagecontent;
import cn.wildfirechat.pojos.MessagePayload;
import cn.wildfirechat.proto.ProtoConstants;
import org.apache.http.util.TextUtils;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* 会议纪要消息内容类
* <p>
* 表示会议纪要类型的消息内容,包含纪要文本、会议标题和会议ID。
* </p>
*/
public class MeetingMinutesMessageContent extends MessageContent {
private String text;
private String title;
private String meetingId;
//必须有个空的构造函数
public MeetingMinutesMessageContent() {
}
public MeetingMinutesMessageContent(String text, String title, String meetingId) {
this.text = text;
this.title = title;
this.meetingId = meetingId;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getMeetingId() {
return meetingId;
}
public void setMeetingId(String meetingId) {
this.meetingId = meetingId;
}
@Override
public int getContentType() {
return ProtoConstants.ContentType.Meeting_Minutes;
}
@Override
public int getPersistFlag() {
return ProtoConstants.PersistFlag.Persist_And_Count;
}
@Override
public MessagePayload encode() {
MessagePayload payload = super.encode();
payload.setContent(text);
payload.setSearchableContent(title);
if (!TextUtils.isEmpty(meetingId)) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("meetingId", meetingId);
payload.setBase64edData(Base64.getEncoder().encodeToString(jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8)));
}
return payload;
}
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
text = payload.getContent();
title = payload.getSearchableContent();
if (!TextUtils.isEmpty(payload.getBase64edData())) {
String jsonStr = new String(Base64.getDecoder().decode(payload.getBase64edData()), StandardCharsets.UTF_8);
try {
JSONObject jsonObject = (JSONObject) new JSONParser().parse(jsonStr);
meetingId = (String) jsonObject.get("meetingId");
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
}
@@ -24,6 +24,8 @@ public class MessageContentFactory {
private static final Map<Integer, Class<? extends MessageContent>> contentClassMap = new ConcurrentHashMap<>();
private static List<Class> buildinMessageContents = Arrays.asList(
MeetingMinutesMessageContent.class,
TranscriptionMessageContent.class,
ArticlesMessageContent.class,
StreamTextGeneratedMessageContent.class,
CallStartMessageContent.class,
@@ -0,0 +1,144 @@
package cn.wildfirechat.sdk.messagecontent;
import cn.wildfirechat.pojos.MessagePayload;
import cn.wildfirechat.proto.ProtoConstants;
import org.apache.http.util.TextUtils;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
/**
* 转换消息内容类(透传消息)
* <p>
* 表示转换类型的透传消息,包含id、会议id、用户id、时间戳、时长和内容。
* </p>
*/
public class TranscriptionMessageContent extends MessageContent {
private long transcriptionId;
private String meetingId;
private String userId;
private long timestamp;
private long duration;
private String content;
//必须有个空的构造函数
public TranscriptionMessageContent() {
}
public TranscriptionMessageContent(long transcriptionId, String meetingId, String userId, long timestamp, long duration, String content) {
this.transcriptionId = transcriptionId;
this.meetingId = meetingId;
this.userId = userId;
this.timestamp = timestamp;
this.duration = duration;
this.content = content;
}
public long getTranscriptionId() {
return transcriptionId;
}
public void setTranscriptionId(long transcriptionId) {
this.transcriptionId = transcriptionId;
}
public String getMeetingId() {
return meetingId;
}
public void setMeetingId(String meetingId) {
this.meetingId = meetingId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public int getContentType() {
return ProtoConstants.ContentType.Transcription;
}
@Override
public int getPersistFlag() {
return ProtoConstants.PersistFlag.Transparent;
}
@Override
public MessagePayload encode() {
MessagePayload payload = super.encode();
JSONObject jsonObject = new JSONObject();
if (transcriptionId > 0) {
jsonObject.put("id", transcriptionId);
}
if (!TextUtils.isEmpty(meetingId)) {
jsonObject.put("meetingId", meetingId);
}
if (!TextUtils.isEmpty(userId)) {
jsonObject.put("userId", userId);
}
if (timestamp > 0) {
jsonObject.put("timestamp", timestamp);
}
if (duration > 0) {
jsonObject.put("duration", duration);
}
if (!TextUtils.isEmpty(content)) {
jsonObject.put("content", content);
}
payload.setContent(jsonObject.toJSONString());
return payload;
}
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
if (!TextUtils.isEmpty(payload.getContent())) {
try {
JSONObject jsonObject = (JSONObject) new JSONParser().parse(payload.getContent());
transcriptionId = ((Number) jsonObject.get("id")).longValue();
meetingId = (String) jsonObject.get("meetingId");
userId = (String) jsonObject.get("userId");
Object ts = jsonObject.get("timestamp");
if (ts != null) {
timestamp = ((Number) ts).longValue();
}
Object dur = jsonObject.get("duration");
if (dur != null) {
duration = ((Number) dur).longValue();
}
content = (String) jsonObject.get("content");
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
}