From ea00ef6b7f85fab91090d5b868d19a8c1318b323 Mon Sep 17 00:00:00 2001 From: heavyrian2012 Date: Fri, 19 Jul 2024 16:54:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=91=E9=80=81=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E7=9A=84=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MediaMessageContentBuilder.java | 19 -- .../MessageContentBuilder.java | 33 --- .../SoundMessageContentBuilder.java | 25 -- .../StreamingTextMessageContentBuilder.java | 48 ---- .../TextMessageContentBuilder.java | 21 -- .../cn/wildfirechat/proto/ProtoConstants.java | 10 + .../main/java/cn/wildfirechat/sdk/Main.java | 216 +++++++++++++--- .../ArticlesMessageContent.java | 125 ++++++++++ .../CallStartMessageContent.java | 205 +++++++++++++++ .../messagecontent/CardMessageContent.java | 133 ++++++++++ .../messagecontent/FileMessageContent.java | 68 +++++ .../messagecontent/ImageMessageContent.java | 55 ++++ .../messagecontent/LinkMessageContent.java | 105 ++++++++ .../LocationMessageContent.java | 99 ++++++++ .../messagecontent/MediaMessageContent.java | 25 ++ .../sdk/messagecontent/MessageContent.java | 44 ++++ .../messagecontent/MessageContentFactory.java | 77 ++++++ .../MultiCallOngoingMessageContent.java | 111 +++++++++ .../NotDeliveredMessageContent.java | 97 ++++++++ .../PTTSoundMessageContent.java | 31 +++ .../RichNotificationMessageContent.java | 63 +++-- .../messagecontent/SoundMessageContent.java | 53 ++++ .../messagecontent/StickerMessageContent.java | 75 ++++++ .../StreamTextGeneratedMessageContent.java | 52 ++++ .../StreamTextGeneratingMessageContent.java | 52 ++++ .../messagecontent/TextMessageContent.java | 81 ++++++ .../TipNotificationMessageContent.java | 48 ++++ .../messagecontent/TypingMessageContent.java | 56 +++++ .../messagecontent/UnknownMessageContent.java | 32 +++ .../messagecontent/VideoMessageContent.java | 94 +++++++ .../cn/wildfirechat/sdk/model/Message.java | 15 ++ .../cn/wildfirechat/sdk/model/QuoteInfo.java | 62 +++++ .../wildfirechat/sdk/utilities/ClassUtil.java | 234 ++++++++++++++++++ 33 files changed, 2271 insertions(+), 193 deletions(-) delete mode 100644 common/src/main/java/cn/wildfirechat/messagecontentbuilder/MediaMessageContentBuilder.java delete mode 100644 common/src/main/java/cn/wildfirechat/messagecontentbuilder/MessageContentBuilder.java delete mode 100644 common/src/main/java/cn/wildfirechat/messagecontentbuilder/SoundMessageContentBuilder.java delete mode 100644 common/src/main/java/cn/wildfirechat/messagecontentbuilder/StreamingTextMessageContentBuilder.java delete mode 100644 common/src/main/java/cn/wildfirechat/messagecontentbuilder/TextMessageContentBuilder.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ArticlesMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CallStartMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CardMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/FileMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ImageMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LinkMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LocationMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MediaMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContentFactory.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MultiCallOngoingMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/NotDeliveredMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/PTTSoundMessageContent.java rename common/src/main/java/cn/wildfirechat/messagecontentbuilder/RichNotificationContentBuilder.java => sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/RichNotificationMessageContent.java (59%) create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/SoundMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StickerMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratedMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratingMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TextMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TipNotificationMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TypingMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/UnknownMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/VideoMessageContent.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/model/Message.java create mode 100644 sdk/src/main/java/cn/wildfirechat/sdk/model/QuoteInfo.java create mode 100755 sdk/src/main/java/cn/wildfirechat/sdk/utilities/ClassUtil.java diff --git a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/MediaMessageContentBuilder.java b/common/src/main/java/cn/wildfirechat/messagecontentbuilder/MediaMessageContentBuilder.java deleted file mode 100644 index 80a20deb..00000000 --- a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/MediaMessageContentBuilder.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.wildfirechat.messagecontentbuilder; - -import cn.wildfirechat.pojos.MessagePayload; - -abstract public class MediaMessageContentBuilder extends MessageContentBuilder{ - private String remoteMediaUrl; - - public MediaMessageContentBuilder remoteMediaUrl(String remoteMediaUrl) { - this.remoteMediaUrl = remoteMediaUrl; - return this; - } - - @Override - protected MessagePayload encodeBase() { - MessagePayload payload = super.encodeBase(); - payload.setRemoteMediaUrl(remoteMediaUrl); - return payload; - } -} diff --git a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/MessageContentBuilder.java b/common/src/main/java/cn/wildfirechat/messagecontentbuilder/MessageContentBuilder.java deleted file mode 100644 index 2f797530..00000000 --- a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/MessageContentBuilder.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.wildfirechat.messagecontentbuilder; - -import cn.wildfirechat.pojos.MessagePayload; - -import java.util.List; - -public abstract class MessageContentBuilder { - private int mentionedType; - private List mentionedTargets; - private String extra; - public MessageContentBuilder mentionedType(int mentionedType) { - this.mentionedType = mentionedType; - return this; - } - public MessageContentBuilder mentionedTargets(List mentionedTargets) { - this.mentionedTargets = mentionedTargets; - return this; - } - - public MessageContentBuilder extra(String extra) { - this.extra = extra; - return this; - } - - protected MessagePayload encodeBase() { - MessagePayload payload = new MessagePayload(); - payload.setMentionedType(mentionedType); - payload.setMentionedTarget(mentionedTargets); - payload.setExtra(extra); - return payload; - } - abstract public MessagePayload build(); -} diff --git a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/SoundMessageContentBuilder.java b/common/src/main/java/cn/wildfirechat/messagecontentbuilder/SoundMessageContentBuilder.java deleted file mode 100644 index 4005748f..00000000 --- a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/SoundMessageContentBuilder.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.wildfirechat.messagecontentbuilder; - -import cn.wildfirechat.pojos.MessagePayload; -import cn.wildfirechat.proto.ProtoConstants; -import org.json.simple.JSONObject; - -public class SoundMessageContentBuilder extends MediaMessageContentBuilder { - private int duration; - public static SoundMessageContentBuilder newBuilder(int duration) { - SoundMessageContentBuilder builder = new SoundMessageContentBuilder(); - builder.duration = duration; - return builder; - } - @Override - public MessagePayload build() { - MessagePayload payload = encodeBase(); - payload.setType(ProtoConstants.ContentType.Voice); - payload.setMediaType(ProtoConstants.MessageMediaType.VOICE); - payload.setPersistFlag(ProtoConstants.PersistFlag.Persist_And_Count); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("duration", duration); - payload.setContent(jsonObject.toJSONString()); - return payload; - } -} diff --git a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/StreamingTextMessageContentBuilder.java b/common/src/main/java/cn/wildfirechat/messagecontentbuilder/StreamingTextMessageContentBuilder.java deleted file mode 100644 index 2960f61f..00000000 --- a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/StreamingTextMessageContentBuilder.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.wildfirechat.messagecontentbuilder; - -import cn.wildfirechat.pojos.MessagePayload; -import cn.wildfirechat.proto.ProtoConstants; -import com.google.gson.Gson; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; - -public class StreamingTextMessageContentBuilder extends MessageContentBuilder{ - private String text; - private String streamId; - private boolean generating; - public static StreamingTextMessageContentBuilder newBuilder(String streamId) { - StreamingTextMessageContentBuilder builder = new StreamingTextMessageContentBuilder(); - builder.generating = false; - builder.streamId = streamId; - return builder; - } - public StreamingTextMessageContentBuilder text(String text) { - this.text = text; - return this; - } - - public StreamingTextMessageContentBuilder generating(boolean generating) { - this.generating = generating; - return this; - } - - @Override - public MessagePayload build() { - MessagePayload payload = encodeBase(); - payload.setSearchableContent(text); - payload.setContent(streamId); - if(generating) { - //正在生成消息的类型是14,存储标记位为透传为4。 - payload.setType(14); - payload.setPersistFlag(4); - } else { - //已经生成消息的类型是15,存储标记位为透传为3。 - payload.setType(15); - payload.setPersistFlag(3); - } - return payload; - } -} diff --git a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/TextMessageContentBuilder.java b/common/src/main/java/cn/wildfirechat/messagecontentbuilder/TextMessageContentBuilder.java deleted file mode 100644 index db71a59c..00000000 --- a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/TextMessageContentBuilder.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.wildfirechat.messagecontentbuilder; - -import cn.wildfirechat.pojos.MessagePayload; -import cn.wildfirechat.proto.ProtoConstants; - -public class TextMessageContentBuilder extends MessageContentBuilder{ - private String text; - public static TextMessageContentBuilder newBuilder(String text) { - TextMessageContentBuilder builder = new TextMessageContentBuilder(); - builder.text = text; - return builder; - } - @Override - public MessagePayload build() { - MessagePayload payload = encodeBase(); - payload.setType(ProtoConstants.ContentType.Text); - payload.setPersistFlag(ProtoConstants.PersistFlag.Persist_And_Count); - payload.setSearchableContent(text); - return payload; - } -} diff --git a/common/src/main/java/cn/wildfirechat/proto/ProtoConstants.java b/common/src/main/java/cn/wildfirechat/proto/ProtoConstants.java index d642b99a..bb622afb 100644 --- a/common/src/main/java/cn/wildfirechat/proto/ProtoConstants.java +++ b/common/src/main/java/cn/wildfirechat/proto/ProtoConstants.java @@ -97,6 +97,10 @@ public class ProtoConstants { int Composited = 11; int Rich_Notification = 12; int Articles = 13; + int StreamingText_Generationg = 14; + int StreamingText_Generated = 15; + int Not_Delivered = 16; + int Ptt_Voice = 23; int Enter_Channel_Chat = 71; int Leave_Channel_Chat = 72; int Recall = 80; @@ -126,6 +130,12 @@ public class ProtoConstants { int Quit_Group_Visible_Notification = 121; int Modify_Group_Extra = 122; int Modify_Group_Member_Extra = 123; + + int Call_Start = 400; + int Call_Accept = 401; + int Call_End = 402; + int Call_Add_Participant = 406; + int Call_Multi_Call_Ongoing = 416; } public interface MessagePersistFlag { diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/Main.java b/sdk/src/main/java/cn/wildfirechat/sdk/Main.java index 33464278..743de5b1 100644 --- a/sdk/src/main/java/cn/wildfirechat/sdk/Main.java +++ b/sdk/src/main/java/cn/wildfirechat/sdk/Main.java @@ -1,15 +1,11 @@ package cn.wildfirechat.sdk; import cn.wildfirechat.common.ErrorCode; -import cn.wildfirechat.messagecontentbuilder.RichNotificationContentBuilder; -import cn.wildfirechat.messagecontentbuilder.StreamingTextMessageContentBuilder; -import cn.wildfirechat.messagecontentbuilder.TextMessageContentBuilder; +import cn.wildfirechat.proto.WFCMessage; +import cn.wildfirechat.sdk.messagecontent.*; import cn.wildfirechat.pojos.*; import cn.wildfirechat.proto.ProtoConstants; import cn.wildfirechat.sdk.model.IMResult; -import cn.wildfirechat.sdk.utilities.AdminHttpUtils; -import cn.wildfirechat.sdk.utilities.RobotHttpUtils; -import com.google.gson.Gson; import com.google.gson.GsonBuilder; import io.netty.util.internal.StringUtil; @@ -53,6 +49,9 @@ public class Main { //admin使用的是18080端口,超级管理接口,理论上不能对外开放端口,也不能让非内部服务知悉密钥。 testAdmin(); + //测试解析数据库中消息内容 + testReadMessageContentFromDB(); + //Robot和Channel都是使用的80端口,第三方可以创建或者为第三方创建,第三方可以使用robot或者channel与IM系统进行对接。 testRobot(); testChannel(); @@ -68,6 +67,7 @@ public class Main { testGroup(); testChatroom(); testMessage(); + testMessageContent(); testChannelApi(); testGeneralApi(); testSensitiveApi(); @@ -716,7 +716,8 @@ public class Main { Conversation conversation = new Conversation(); conversation.setTarget("ff2"); conversation.setType(ProtoConstants.ConversationType.ConversationType_Private); - MessagePayload payload = TextMessageContentBuilder.newBuilder("Hello world").build(); + TextMessageContent textMessageContent = new TextMessageContent("Hello world"); + MessagePayload payload = textMessageContent.encode(); IMResult resultSendMessage = MessageAdmin.sendMessage("ff1", conversation, payload, null); if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) { @@ -726,24 +727,6 @@ public class Main { System.exit(-1); } - RichNotificationContentBuilder builder = RichNotificationContentBuilder.newBuilder("产品审核通知", "您好,您的SSL证书以审核通过并成功办理,请关注", "https://www.baidu.com") - .remark("谢谢惠顾") - .exName("证书小助手") - .appId("1234567890") - .addItem("登陆账户", "野火IM", "#173177") - .addItem("产品名称", "域名wildifrechat.cn申请的免费SSL证书", "#173177") - .addItem("审核通过", "通过", "#173177") - .addItem("说明", "请登陆账户查看处理", "#173177"); - - - resultSendMessage = MessageAdmin.sendMessage("ff1", conversation, builder.build(), null); - if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) { - System.out.println("send message success"); - } else { - System.out.println("send message failure"); - System.exit(-1); - } - IMResult outputMessageDataIMResult = MessageAdmin.getMessage(resultSendMessage.result.getMessageUid()); if(outputMessageDataIMResult != null && outputMessageDataIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && outputMessageDataIMResult.getResult().getMessageId() == resultSendMessage.getResult().getMessageUid()) { System.out.println("get message success"); @@ -844,14 +827,179 @@ public class Main { System.out.println("failure"); } - testStreamingText(); } - static void testStreamingText() throws Exception { + //*********************************************** + //**** 发送各种消息。 + //*********************************************** + static void testMessageContent() throws Exception { + String sender = "userId2"; Conversation conversation = new Conversation(); - conversation.setTarget("uygqmws2k"); + conversation.setTarget("3ygqmws2k"); conversation.setType(ProtoConstants.ConversationType.ConversationType_Private); + //测试发送文本消息 + TextMessageContent textMessageContent = new TextMessageContent("测试文本消息"); + //消息转成Payload并发送 + MessagePayload payload = textMessageContent.encode(); + IMResult resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试发送语音消息 + SoundMessageContent soundMessageContent = new SoundMessageContent(); + //语音文件时长,单位秒 + soundMessageContent.setDuration(7); + //语音文件格式为amr或者mp3,需要先上传到对象存储服务。 + soundMessageContent.setRemoteMediaUrl("https://media.wfcoss.cn/firechat/voice_message_sample.amr"); + //消息转成Payload并发送 + payload = soundMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试发送图片消息 + ImageMessageContent imageMessageContent = new ImageMessageContent(); + //base64edData为图片的缩略图。缩略图的生成规则是,把图片压缩到120X120大小的方框内,45%的质量压缩为JPG格式,再把二进制做base64编码得到字符串。 + String thumbnailBase64edData = "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"; + imageMessageContent.setThumbnailBytes(Base64.getDecoder().decode(thumbnailBase64edData)); + //图片地址,发送前需要先上传到对象存储服务。 + imageMessageContent.setRemoteMediaUrl("https://media.wfcoss.cn/firechat/image_message_sample.jpg"); + //消息转成Payload并发送 + payload = imageMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试发送视频消息 + VideoMessageContent videoMessageContent = new VideoMessageContent(); + //base64edData为视频的首帧的缩略图。缩略图的生成规则是,把图片压缩到120X120大小的方框内,45%的质量压缩为JPG格式,再把二进制做base64编码得到字符串。 + thumbnailBase64edData = "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"; + videoMessageContent.setThumbnailBytes(Base64.getDecoder().decode(thumbnailBase64edData)); + //视频时长,单位秒 + videoMessageContent.setDuration(3); + //视频地址,发送前需要先上传到对象存储服务。 + videoMessageContent.setRemoteMediaUrl("https://media.wfcoss.cn/firechat/video_message_sample.mov"); + //消息转成Payload并发送 + payload = videoMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试发送位置消息 + LocationMessageContent locationMessageContent = new LocationMessageContent(); + //base64edData为位置图片的缩略图。缩略图的生成规则是,把图片压缩到120X120大小的方框内,45%的质量压缩为JPG格式,再把二进制做base64编码得到字符串。 + thumbnailBase64edData = "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"; + locationMessageContent.setThumbnailByte(Base64.getDecoder().decode(thumbnailBase64edData)); + locationMessageContent.setTitle("中国北京市海淀区阜成路北二街131号"); + //设置经纬度 + locationMessageContent.setLatitude(39.926537312885166); + locationMessageContent.setLongitude(116.32154022158235); + //消息转成Payload并发送 + payload = locationMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试发送文件消息 + FileMessageContent fileMessageContent = new FileMessageContent(); + //设置文件名 + fileMessageContent.setName("野火产品简介.pptx"); + //设置文件大小 + fileMessageContent.setSize(38394); + //设置文件链接 + fileMessageContent.setRemoteMediaUrl("https://media.wfcoss.cn/firechat/file_message_sample.pptx"); + //消息转成Payload并发送 + payload = fileMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试动态表情消息 + StickerMessageContent stickerMessageContent = new StickerMessageContent(); + stickerMessageContent.setWidth(753); + stickerMessageContent.setHeight(960); + stickerMessageContent.setRemoteMediaUrl("https://media.wfcoss.cn/firechat/sticker_message_sample.jpg"); + //消息转成Payload并发送 + payload = stickerMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试链接消息 + LinkMessageContent linkMessageContent = new LinkMessageContent(); + linkMessageContent.setTitle("野火IM开发手册"); + linkMessageContent.setUrl("https://docs.wildfirechat.cn"); + linkMessageContent.setThumbnailUrl("https://docs.wildfirechat.cn/favicon.ico"); + linkMessageContent.setContentDigest("野火IM开发手册,关于野火的所有知识都在这里!"); + //消息转成Payload并发送 + payload = linkMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试名片消息 + CardMessageContent cardMessageContent = new CardMessageContent(); + //类型:0,用户;1,群组;2,聊天室;3,频道 + cardMessageContent.setType(0); + cardMessageContent.setTarget("FireRobot"); + cardMessageContent.setName("FireRobot"); + cardMessageContent.setPortrait("https://cdn2.wildfirechat.net/robot.png"); + cardMessageContent.setDisplayName("小火"); + cardMessageContent.setFrom(sender); + //消息转成Payload并发送 + payload = cardMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试提醒消息 + TipNotificationMessageContent tipNotificationMessageContent = new TipNotificationMessageContent(); + tipNotificationMessageContent.setTip("这是一个提醒小灰条消息"); + //消息转成Payload并发送 + payload = tipNotificationMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试富通知消息 + RichNotificationMessageContent richNotificationMessageContent = new RichNotificationMessageContent("产品审核通知", "您好,您的SSL证书以审核通过并成功办理,请关注", "https://www.wildfirechat.cn") + .remark("谢谢惠顾") + .exName("证书小助手") + .appId("1234567890") + .addItem("登陆账户", "野火IM", "#173177") + .addItem("产品名称", "域名wildifrechat.cn申请的免费SSL证书", "#173177") + .addItem("审核通过", "通过", "#173177") + .addItem("说明", "请登陆账户查看处理", "#173177"); + //消息转成Payload并发送 + payload = richNotificationMessageContent.encode(); + resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); + checkSendMessageResult(resultSendMessage); + + //测试流式文本消息 + testStreamingText(sender, conversation); + } + + static void testReadMessageContentFromDB() throws Exception { + //从数据库t_messages_x表中读取到消息内容字段_data的二进制数据为 + byte[] data = {8,1,18,5,72,101,108,108,111,64,3}; + //1. 先把二进制数据转化为协议栈消息内容。 + WFCMessage.MessageContent protoContent = WFCMessage.MessageContent.parseFrom(data); + //2. 调用MessageContentFactory接口解析为消息内容。 + MessageContent messageContent = MessageContentFactory.decodeMessageContent(protoContent); + //3. 检查是哪种消息,如果没有定义,会回落到UnknownMessageContent。 + if(messageContent instanceof TextMessageContent) { + TextMessageContent txt = (TextMessageContent)messageContent; + System.out.println("读取到的是文本消息,内容为:" + txt.getText()); + } else if(messageContent instanceof ImageMessageContent) { + ImageMessageContent img = (ImageMessageContent) messageContent; + System.out.println("读取到的是图片消息,图片链接为:" + img.getRemoteMediaUrl()); + } else if(messageContent instanceof SoundMessageContent) { + SoundMessageContent sound = (SoundMessageContent) messageContent; + System.out.println("读取到的是声音消息,声音链接为:" + sound.getRemoteMediaUrl()); + } + } + + static void checkSendMessageResult(IMResult resultSendMessage) { + if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) { + System.out.println("send message success"); + } else { + System.out.println("send message failure"); + System.exit(-1); + } + } + + static void testStreamingText(String sender, Conversation conversation) throws Exception { String fullText = "北京野火无限网络科技有限公司是成立于2019年底的一家科技创新企业,公司的主要目标是为广大企业和单位提供优质可控、私有部署的即时通讯和实时音视频能力,为社会信息化水平提高作出自己的贡献。\n" + "\n" + "野火IM是公司研发一套自主可控的即时通讯组件,具有全部私有化、功能齐全、协议稳定可靠、全平台支持、安全性高和支持国产化等技术特点。客户端分层设计,既可开箱即用,也可与现有系统深度融合。具有完善的服务端API和自定义消息功能,可以任意扩展功能。代码开源率高,方便二次开发和使用。支持多人实时音视频和会议功能,线上沟通更通畅。\n" + @@ -867,9 +1015,16 @@ public class Main { boolean finish = i >= fullText.length(); String partText = finish?fullText:fullText.substring(0, i); - MessagePayload payload = StreamingTextMessageContentBuilder.newBuilder(streamId).text(partText).generating(!finish).build(); + MessageContent messageContent; + if(finish) { + messageContent = new StreamTextGeneratedMessageContent(partText, streamId); + } else { + messageContent = new StreamTextGeneratingMessageContent(partText, streamId); + } + //消息转成Payload并发送 + MessagePayload payload = messageContent.encode(); - IMResult resultSendMessage = MessageAdmin.sendMessage("admin", conversation, payload, null); + IMResult resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null); if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) { System.out.println("send message success"); } else { @@ -881,6 +1036,7 @@ public class Main { } } + //*********************************************** //**** 测试频道功能 //*********************************************** diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ArticlesMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ArticlesMessageContent.java new file mode 100644 index 00000000..b74b58d4 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ArticlesMessageContent.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + + +public class ArticlesMessageContent extends MessageContent { + public Article topArticle; + public ArrayList
subArticles; + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Articles; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setSearchableContent(topArticle.title); + JSONObject object = new JSONObject(); + + object.put("top", topArticle.toJson()); + if (subArticles != null) { + JSONArray jsonArray = new JSONArray(); + object.put("subArticles", jsonArray); + for (Article article : subArticles) { + jsonArray.add(article.toJson()); + } + } + payload.setBase64edData(Base64.getEncoder().encodeToString(object.toString().getBytes())); + + + return payload; + } + + @Override + public void decode(MessagePayload payload) { + try { + JSONObject object = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData()))); + JSONObject topObj = (JSONObject) object.get("top"); + this.topArticle = Article.fromJson(topObj); + JSONArray jsonArray = (JSONArray) object.get("subArticles"); + if (jsonArray != null && jsonArray.size() > 0) { + this.subArticles = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + subArticles.add(Article.fromJson((JSONObject) jsonArray.get(i))); + } + } + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + + public List toLinkMessageContent() { + List contents = new ArrayList<>(); + contents.add(this.topArticle.toLinkMessageContent()); + if (this.subArticles != null) { + for (Article article : subArticles) { + contents.add(article.toLinkMessageContent()); + } + } + return contents; + } + + public static class Article { + public String articleId; + public String cover; + public String title; + public String digest; + public String url; + boolean readReport; + + JSONObject toJson() { + JSONObject obj = new JSONObject(); + obj.put("id", articleId); + obj.put("cover", cover); + obj.put("title", title); + obj.put("digest", digest); + obj.put("url", url); + obj.put("rr", readReport); + + + return obj; + } + + static Article fromJson(JSONObject obj) { + Article article = new Article(); + article.articleId = (String) obj.get("id"); + article.cover = (String) obj.get("cover"); + article.title = (String) obj.get("title"); + article.digest = (String) obj.get("digest"); + article.url = (String) obj.get("url"); + article.readReport = (boolean) obj.get("rr"); + return article; + } + + public LinkMessageContent toLinkMessageContent() { + LinkMessageContent content = new LinkMessageContent(this.title, this.url); + content.setContentDigest(this.digest); + content.setThumbnailUrl(this.cover); + return content; + } + + public Article() { + } + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CallStartMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CallStartMessageContent.java new file mode 100644 index 00000000..7a070bcf --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CallStartMessageContent.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import io.netty.util.internal.StringUtil; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + +/** + * Created by heavyrain lee on 2017/12/6. + */ + +public class CallStartMessageContent extends MessageContent { + private String callId; + // 多人视音频是有效,不包含自己,一对一忽略此参数 + private List targetIds; + private long connectTime; + private long endTime; + private boolean audioOnly; + private String pin; + + + /** + * 0, UnKnown, + * 1, Busy, + * 2, SignalError, + * 3, Hangup, + * 4, MediaError, + * 5, RemoteHangup, + * 6, OpenCameraFailure, + * 7, Timeout, + * 8, AcceptByOtherClient + */ + private int status; + + /** + * 0,未知;1,多人版音视频;2,高级版音视频 + */ + private int type; + + public CallStartMessageContent() { + } + + public CallStartMessageContent(String callId, List targetIds, boolean audioOnly) { + this.callId = callId; + this.audioOnly = audioOnly; + this.targetIds = targetIds; + } + + public String getCallId() { + return callId; + } + + public void setCallId(String callId) { + this.callId = callId; + } + + public long getConnectTime() { + return connectTime; + } + + public void setConnectTime(long connectTime) { + this.connectTime = connectTime; + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public boolean isAudioOnly() { + return audioOnly; + } + + public void setAudioOnly(boolean audioOnly) { + this.audioOnly = audioOnly; + } + + public List getTargetIds() { + return targetIds; + } + + public void setTargetIds(List targetIds) { + this.targetIds = targetIds; + } + + public String getPin() { + return pin; + } + + public void setPin(String pin) { + this.pin = pin; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Call_Start; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setContent(callId); + payload.setPushContent("音视频通话邀请"); + + JSONObject objWrite = new JSONObject(); + if (connectTime > 0) { + objWrite.put("c", connectTime); + } + + if (endTime > 0) { + objWrite.put("e", endTime); + } + + if (status > 0) { + objWrite.put("s", status); + } + + objWrite.put("t", targetIds.get(0)); + JSONArray ts = new JSONArray(); + ts.addAll(targetIds); + objWrite.put("ts", ts); + objWrite.put("a", audioOnly ? 1 : 0); + objWrite.put("p", pin); + if (this.type > 0) { + objWrite.put("ty", this.type); + } + + payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes())); + + JSONObject pushDataWrite = new JSONObject(); + pushDataWrite.put("callId", callId); + pushDataWrite.put("audioOnly", audioOnly); + if (targetIds != null && targetIds.size() > 0) { + pushDataWrite.put("participants", targetIds); + } + payload.setPushData(pushDataWrite.toString()); + return payload; + } + + + @Override + public void decode(MessagePayload payload) { + callId = payload.getContent(); + + try { + if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) { + JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData()))); + connectTime = (long) jsonObject.get("c"); + endTime = (long) jsonObject.get("e"); + status = (int) jsonObject.get("s"); + pin = (String) jsonObject.get("p"); + type = (int) jsonObject.get("ty"); + JSONArray array = (JSONArray) jsonObject.get("ts"); + targetIds = new ArrayList<>(); + if (array == null) { + targetIds.add((String) jsonObject.get("t")); + } else { + for (int i = 0; i < array.size(); i++) { + if (array.get(i) instanceof String) { + targetIds.add((String) array.get(i)); + } + } + } + audioOnly = (int)jsonObject.get("a") > 0; + } + } catch (ParseException e) { + throw new RuntimeException(e); + } + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CardMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CardMessageContent.java new file mode 100644 index 00000000..e97a1dda --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CardMessageContent.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import io.netty.util.internal.StringUtil; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.Base64; + +public class CardMessageContent extends MessageContent { + /** + * 0,用户;1,群组;2,聊天室;3,频道 + */ + private int type; + private String target; + // 用户名,一般是type为用户时使用 + private String name; + private String displayName; + private String portrait; + private String from; + + public CardMessageContent() { + } + + public CardMessageContent(int type, String target, String displayName, String portrait, String from) { + this.type = type; + this.target = target; + this.displayName = displayName; + this.portrait = portrait; + this.from = from; + } + + public String getTarget() { + return target; + } + + public void setTarget(String target) { + this.target = target; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getPortrait() { + return portrait; + } + + public void setPortrait(String portrait) { + this.portrait = portrait; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Name_Card; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setContent(target); + JSONObject objWrite = new JSONObject(); + objWrite.put("t", type); + objWrite.put("n", name); + objWrite.put("d", displayName); + objWrite.put("p", portrait); + objWrite.put("f", from); + + payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes())); + return payload; + } + + + @Override + public void decode(MessagePayload payload) { + target = payload.getContent(); + try { + if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) { + JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData()))); + type = (int) jsonObject.get("t"); + name = (String) jsonObject.get("n"); + displayName = (String) jsonObject.get("d"); + portrait = (String) jsonObject.get("p"); + from = (String) jsonObject.get("f"); + } + } catch (ParseException e) { + throw new RuntimeException(e); + } + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/FileMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/FileMessageContent.java new file mode 100644 index 00000000..ab004bd1 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/FileMessageContent.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; + +public class FileMessageContent extends MediaMessageContent { + private String name; + private int size; + private static final String FILE_NAME_PREFIX = "[文件] "; + + + @Override + public int getContentType() { + return ProtoConstants.ContentType.File; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setSearchableContent(name); + payload.setContent(size + ""); + + return payload; + } + + public String getName() { + return name; + } + + public int getSize() { + return size; + } + + public void setName(String name) { + this.name = name; + } + + public void setSize(int size) { + this.size = size; + } + + @Override + public void decode(MessagePayload payload) { + super.decodeBase(payload); + + if (payload.getSearchableContent().startsWith(FILE_NAME_PREFIX)) { + name = payload.getSearchableContent().substring(payload.getSearchableContent().indexOf(FILE_NAME_PREFIX) + FILE_NAME_PREFIX.length()); + } else { + name = payload.getSearchableContent(); + } + size = Integer.parseInt(payload.getContent()); + } + + @Override + protected int getMediaType() { + return ProtoConstants.MessageMediaType.FILE; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ImageMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ImageMessageContent.java new file mode 100644 index 00000000..a51af1ad --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ImageMessageContent.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; + +import java.util.Base64; + +public class ImageMessageContent extends MediaMessageContent { + private byte[] thumbnailBytes; + + + public void setThumbnailBytes(byte[] thumbnailBytes) { + this.thumbnailBytes = thumbnailBytes; + } + + public byte[] getThumbnailBytes() { + return thumbnailBytes; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Image; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setSearchableContent("[图片]"); + payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes)); + + return payload; + } + + + @Override + public void decode(MessagePayload payload) { + super.decodeBase(payload); + thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData()); + } + + @Override + protected int getMediaType() { + return ProtoConstants.MessageMediaType.IMAGE; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LinkMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LinkMessageContent.java new file mode 100644 index 00000000..b55eff3d --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LinkMessageContent.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import io.netty.util.internal.StringUtil; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.Base64; + +public class LinkMessageContent extends MessageContent { + private String title; + private String contentDigest; + private String url; + private String thumbnailUrl; + + public LinkMessageContent() { + } + + public LinkMessageContent(String title, String url) { + this.title = title; + this.url = url; + } + + public String getContentDigest() { + return contentDigest; + } + + public void setContentDigest(String contentDigest) { + this.contentDigest = contentDigest; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getThumbnailUrl() { + return thumbnailUrl; + } + + public void setThumbnailUrl(String thumbnailUrl) { + this.thumbnailUrl = thumbnailUrl; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Link; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + + + payload.setSearchableContent(title); + JSONObject objWrite = new JSONObject(); + objWrite.put("d", contentDigest); + objWrite.put("u", url); + objWrite.put("t", thumbnailUrl); + payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes())); + + return payload; + } + + + @Override + public void decode(MessagePayload payload) { + title = payload.getSearchableContent(); + + + try { + if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) { + JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData()))); + contentDigest = (String) jsonObject.get("d"); + url = (String) jsonObject.get("u"); + thumbnailUrl = (String) jsonObject.get("t"); + } + } catch (ParseException e) { + throw new RuntimeException(e); + } + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LocationMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LocationMessageContent.java new file mode 100644 index 00000000..ca1bf4fb --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LocationMessageContent.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import io.netty.util.internal.StringUtil; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.Base64; + +public class LocationMessageContent extends MessageContent { + private String title; + public byte[] thumbnailByte; + private double longitude; + private double latitude; + + public LocationMessageContent() { + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public byte[] getThumbnailByte() { + return thumbnailByte; + } + + public void setThumbnailByte(byte[] thumbnailByte) { + this.thumbnailByte = thumbnailByte; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Location; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setSearchableContent(title); + payload.setBase64edData(Base64.getEncoder().encodeToString(this.thumbnailByte)); + + JSONObject objWrite = new JSONObject(); + objWrite.put("lat", latitude); + objWrite.put("long", longitude); + + payload.setContent(objWrite.toString()); + + return payload; + } + + + @Override + public void decode(MessagePayload payload) { + if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) { + this.thumbnailByte = Base64.getDecoder().decode(payload.getBase64edData()); + } + title = payload.getSearchableContent(); + try { + if (payload.getContent() != null) { + JSONObject jsonObject = (JSONObject) new JSONParser().parse(payload.getContent()); + latitude = (double) jsonObject.get("lat"); + longitude = (double) jsonObject.get("long"); + } + } catch (ParseException e) { + throw new RuntimeException(e); + } + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MediaMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MediaMessageContent.java new file mode 100644 index 00000000..ccc91eea --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MediaMessageContent.java @@ -0,0 +1,25 @@ +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; + +abstract public class MediaMessageContent extends MessageContent { + private String remoteMediaUrl; + + public String getRemoteMediaUrl() { + return remoteMediaUrl; + } + + public void setRemoteMediaUrl(String remoteMediaUrl) { + this.remoteMediaUrl = remoteMediaUrl; + } + + @Override + protected MessagePayload encodeBase() { + MessagePayload payload = super.encodeBase(); + payload.setRemoteMediaUrl(remoteMediaUrl); + payload.setMediaType(getMediaType()); + return payload; + } + + protected abstract int getMediaType(); +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContent.java new file mode 100644 index 00000000..41282d79 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContent.java @@ -0,0 +1,44 @@ +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; + +import java.util.List; + +public abstract class MessageContent { + private int mentionedType; + private List mentionedTargets; + private String extra; + public MessageContent mentionedType(int mentionedType) { + this.mentionedType = mentionedType; + return this; + } + public MessageContent mentionedTargets(List mentionedTargets) { + this.mentionedTargets = mentionedTargets; + return this; + } + + public MessageContent extra(String extra) { + this.extra = extra; + return this; + } + + protected MessagePayload encodeBase() { + MessagePayload payload = new MessagePayload(); + payload.setType(getContentType()); + payload.setPersistFlag(getPersistFlag()); + payload.setMentionedType(mentionedType); + payload.setMentionedTarget(mentionedTargets); + payload.setExtra(extra); + return payload; + } + + protected void decodeBase(MessagePayload payload) { + this.mentionedType = payload.getMentionedType(); + this.mentionedTargets = payload.getMentionedTarget(); + this.extra = payload.getExtra(); + } + abstract public int getContentType(); + abstract public int getPersistFlag(); + abstract public MessagePayload encode(); + abstract public void decode(MessagePayload payload); +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContentFactory.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContentFactory.java new file mode 100644 index 00000000..9c051d88 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContentFactory.java @@ -0,0 +1,77 @@ +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.Conversation; +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.WFCMessage; +import cn.wildfirechat.sdk.model.Message; +import cn.wildfirechat.sdk.utilities.ClassUtil; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class MessageContentFactory { + private static final Map> contentClassMap = new ConcurrentHashMap<>(); + + static { + registerAllMessageContent(); + } + + public static Message decodeMessage(WFCMessage.Message protoMessage) { + Message message = new Message(); + message.content = decodeMessageContent(protoMessage.getContent()); + WFCMessage.Conversation protoConversation = protoMessage.getConversation(); + message.conversation = new Conversation(protoConversation.getType(), protoConversation.getTarget(), protoConversation.getLine()); + message.messageUid = protoMessage.getMessageId(); + message.sender = protoMessage.getFromUser(); + message.serverTime = protoMessage.getServerTimestamp(); + message.toUsers = protoMessage.getToList(); + return message; + } + + public static MessageContent decodeMessageContent(WFCMessage.MessageContent protoMessageContent) { + MessagePayload payload = MessagePayload.fromProtoMessageContent(protoMessageContent); + return decodeMessageContent(payload); + } + + public static MessageContent decodeMessageContent(MessagePayload messagePayload) { + Class cls = contentClassMap.get(messagePayload.getType()); + MessageContent messageContent; + if(cls != null) { + try { + messageContent = cls.newInstance(); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } else { + messageContent = new UnknownMessageContent(); + } + messageContent.decodeBase(messagePayload); + messageContent.decode(messagePayload); + return messageContent; + } + + private static void registerAllMessageContent() { + try { + for (Class cls : ClassUtil.getAllAssignedClass(MessageContent.class)) { + if(!Modifier.isAbstract(cls.getModifiers())) { + try { + MessageContent content = (MessageContent)cls.newInstance(); + contentClassMap.put(content.getContentType(), cls); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MultiCallOngoingMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MultiCallOngoingMessageContent.java new file mode 100644 index 00000000..4e7d1a5d --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MultiCallOngoingMessageContent.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + +public class MultiCallOngoingMessageContent extends MessageContent { + private String callId; + private String initiator; + private boolean audioOnly; + private List targets; + + public MultiCallOngoingMessageContent() { + } + + public MultiCallOngoingMessageContent(String callId, String initiator, boolean audioOnly, List targets) { + this.callId = callId; + this.initiator = initiator; + this.audioOnly = audioOnly; + this.targets = targets; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Call_Multi_Call_Ongoing; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Transparent; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setContent(callId); + JSONObject object = new JSONObject(); + object.put("initiator", this.initiator); + JSONArray arr = new JSONArray(); + for (int i = 0; i < targets.size(); i++) { + arr.add(i, targets.get(i)); + } + object.put("targets", arr); + object.put("audioOnly", this.audioOnly ? 1 : 0); + payload.setBase64edData(Base64.getEncoder().encodeToString(object.toString().getBytes())); + + return payload; + } + + @Override + public void decode(MessagePayload payload) { + this.callId = payload.getContent(); + try { + JSONObject object = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData()))); + this.initiator = (String) object.get("initiator"); + this.targets = new ArrayList<>(); + JSONArray array = (JSONArray) object.get("targets"); + if (array != null) { + for (int i = 0; i < array.size(); i++) { + targets.add((String) array.get(i)); + } + } + this.audioOnly = (int)object.get("audioOnly") == 1; + } catch (ParseException e) { + e.printStackTrace(); + } + } + + public String getCallId() { + return callId; + } + + public void setCallId(String callId) { + this.callId = callId; + } + + public String getInitiator() { + return initiator; + } + + public void setInitiator(String initiator) { + this.initiator = initiator; + } + + public boolean isAudioOnly() { + return audioOnly; + } + + public void setAudioOnly(boolean audioOnly) { + this.audioOnly = audioOnly; + } + + public List getTargets() { + return targets; + } + + public void setTargets(List targets) { + this.targets = targets; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/NotDeliveredMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/NotDeliveredMessageContent.java new file mode 100644 index 00000000..d7a18986 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/NotDeliveredMessageContent.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + +public class NotDeliveredMessageContent extends MessageContent { + // 请求的类型,1 发送消息,2 撤回消息,3 删除消息 + private int type; + + // 发送的消息 uid + private long messageUid; + + // 是全部失败,还是部分失败 + private boolean allFailure; + + // 部分失败时,失败的用户 id 列表 + private List userIds; + + // 归属IM服务请求桥接服务出现的错误,有可能是桥接服务没有配置,或者不可用。 + private int localImErrorCode; + + // 归属桥接服务出现的错误 + private int localBridgeErrorCode; + + // 远端桥接服务出现的错误 + private int remoteBridgeErrorCode; + + // 远端IM服务出现的错误 + private int remoteServerErrorCode; + + // 错误提示信息 + private String errorMessage; + + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Not_Delivered; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + JSONObject obj = new JSONObject(); + obj.put("mid", this.messageUid); + obj.put("all", this.allFailure); + obj.put("us", this.userIds); + obj.put("lme", this.localImErrorCode); + obj.put("lbe", this.localBridgeErrorCode); + obj.put("rbe", this.remoteBridgeErrorCode); + obj.put("rme", this.remoteServerErrorCode); + obj.put("em", this.errorMessage); + payload.setBase64edData(Base64.getEncoder().encodeToString(obj.toString().getBytes())); + return payload; + } + + @Override + public void decode(MessagePayload payload) { + try { + + JSONObject obj = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData()))); + this.messageUid = (long) obj.get("mid"); + this.allFailure = (boolean) obj.get("all"); + this.userIds = new ArrayList<>(); + JSONArray arr = (JSONArray) obj.get("us"); + if (arr != null) { + for (int i = 0; i < arr.size(); i++) { + this.userIds.add((String) arr.get(i)); + } + } + this.localImErrorCode = (int) obj.get("lme"); + this.localBridgeErrorCode = (int) obj.get("lbe"); + this.remoteBridgeErrorCode = (int) obj.get("rbe"); + this.remoteServerErrorCode = (int) obj.get("rme"); + this.errorMessage = (String) obj.get("em"); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/PTTSoundMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/PTTSoundMessageContent.java new file mode 100644 index 00000000..e8e5caf5 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/PTTSoundMessageContent.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import org.json.simple.JSONObject; + +public class PTTSoundMessageContent extends SoundMessageContent { + + public PTTSoundMessageContent() { + super(); + } + + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encode(); + payload.setSearchableContent("[对讲语音]"); + + return payload; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Ptt_Voice; + } +} diff --git a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/RichNotificationContentBuilder.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/RichNotificationMessageContent.java similarity index 59% rename from common/src/main/java/cn/wildfirechat/messagecontentbuilder/RichNotificationContentBuilder.java rename to sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/RichNotificationMessageContent.java index 6936bd48..b56f8c6d 100644 --- a/common/src/main/java/cn/wildfirechat/messagecontentbuilder/RichNotificationContentBuilder.java +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/RichNotificationMessageContent.java @@ -1,4 +1,4 @@ -package cn.wildfirechat.messagecontentbuilder; +package cn.wildfirechat.sdk.messagecontent; import cn.wildfirechat.pojos.MessagePayload; import cn.wildfirechat.proto.ProtoConstants; @@ -9,7 +9,7 @@ import org.json.simple.JSONObject; import java.nio.charset.StandardCharsets; import java.util.Base64; -public class RichNotificationContentBuilder extends MessageContentBuilder{ +public class RichNotificationMessageContent extends MessageContent { private String title; private String desc; private String remark; @@ -19,34 +19,51 @@ public class RichNotificationContentBuilder extends MessageContentBuilder{ private String exUrl; private String appId; - public static RichNotificationContentBuilder newBuilder(String title, String desc, String exUrl) { - RichNotificationContentBuilder builder = new RichNotificationContentBuilder(); - builder.title = title; - builder.desc = desc; - builder.exUrl = exUrl; - return builder; + //必须有个空的构造函数 + public RichNotificationMessageContent() { } - public RichNotificationContentBuilder remark(String remark) { + public RichNotificationMessageContent(String title, String desc, String exUrl) { + this.title = title; + this.desc = desc; + this.exUrl = exUrl; + } + + public RichNotificationMessageContent title(String title) { + this.title = title; + return this; + } + + public RichNotificationMessageContent desc(String desc) { + this.desc = desc; + return this; + } + + public RichNotificationMessageContent exUrl(String exUrl) { + this.exUrl = exUrl; + return this; + } + + public RichNotificationMessageContent remark(String remark) { this.remark = remark; return this; } - public RichNotificationContentBuilder exName(String exName) { + public RichNotificationMessageContent exName(String exName) { this.exName = exName; return this; } - public RichNotificationContentBuilder exPortrait(String exPortrait) { + public RichNotificationMessageContent exPortrait(String exPortrait) { this.exPortrait = exPortrait; return this; } - public RichNotificationContentBuilder appId(String appId) { + public RichNotificationMessageContent appId(String appId) { this.appId = appId; return this; } - public RichNotificationContentBuilder addItem(String key, String value) { + public RichNotificationMessageContent addItem(String key, String value) { return addItem(key, value, null); } - public RichNotificationContentBuilder addItem(String key, String value, String color) { + public RichNotificationMessageContent addItem(String key, String value, String color) { if(this.datas == null) { this.datas = new JSONArray(); } @@ -61,10 +78,18 @@ public class RichNotificationContentBuilder extends MessageContentBuilder{ } @Override - public MessagePayload build() { + public int getContentType() { + return ProtoConstants.ContentType.Rich_Notification; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { MessagePayload payload = encodeBase(); - payload.setType(ProtoConstants.ContentType.Rich_Notification); - payload.setPersistFlag(ProtoConstants.PersistFlag.Persist_And_Count); payload.setPushContent(title); payload.setContent(desc); JSONObject jsonObject = new JSONObject(); @@ -85,4 +110,8 @@ public class RichNotificationContentBuilder extends MessageContentBuilder{ return payload; } + + @Override + public void decode(MessagePayload payload) { + } } diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/SoundMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/SoundMessageContent.java new file mode 100644 index 00000000..eb4f9425 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/SoundMessageContent.java @@ -0,0 +1,53 @@ +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import org.json.simple.JSONObject; + +public class SoundMessageContent extends MediaMessageContent { + private int duration; + + //必须有个空的构造函数 + public SoundMessageContent() { + } + + public SoundMessageContent(int duration) { + this.duration = duration; + } + + public int getDuration() { + return duration; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Voice; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public void decode(MessagePayload payload) { + } + + @Override + public MessagePayload encode() { + MessagePayload payload = encodeBase(); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("duration", duration); + payload.setContent(jsonObject.toJSONString()); + return payload; + } + + @Override + protected int getMediaType() { + return ProtoConstants.MessageMediaType.VOICE; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StickerMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StickerMessageContent.java new file mode 100644 index 00000000..c9245b39 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StickerMessageContent.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.Base64; + +public class StickerMessageContent extends MediaMessageContent { + public int width; + public int height; + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setSearchableContent("[动态表情]"); + JSONObject objWrite = new JSONObject(); + objWrite.put("x", width); + objWrite.put("y", height); + payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes())); + + return payload; + } + + + @Override + public void decode(MessagePayload payload) { + super.decodeBase(payload); + + try { + JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData()))); + width = (int) jsonObject.get("x"); + height = (int) jsonObject.get("y"); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + @Override + protected int getMediaType() { + return ProtoConstants.MessageMediaType.STICKER; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Sticker; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratedMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratedMessageContent.java new file mode 100644 index 00000000..ab85d004 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratedMessageContent.java @@ -0,0 +1,52 @@ +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; + +public class StreamTextGeneratedMessageContent extends MessageContent { + private String text; + private String streamId; + + //必须有个空的构造函数 + public StreamTextGeneratedMessageContent() { + } + + public StreamTextGeneratedMessageContent(String text, String streamId) { + this.text = text; + this.streamId = streamId; + } + + public StreamTextGeneratedMessageContent text(String text) { + this.text = text; + return this; + } + + public StreamTextGeneratedMessageContent streamId(String streamId) { + this.streamId = streamId; + return this; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.StreamingText_Generated; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public void decode(MessagePayload payload) { + this.streamId = payload.getContent(); + this.text = payload.getSearchableContent(); + } + + @Override + public MessagePayload encode() { + MessagePayload payload = encodeBase(); + payload.setSearchableContent(text); + payload.setContent(streamId); + return payload; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratingMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratingMessageContent.java new file mode 100644 index 00000000..ba4f0caf --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratingMessageContent.java @@ -0,0 +1,52 @@ +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; + +public class StreamTextGeneratingMessageContent extends MessageContent { + private String text; + private String streamId; + + //必须有个空的构造函数 + public StreamTextGeneratingMessageContent() { + } + + public StreamTextGeneratingMessageContent(String text, String streamId) { + this.text = text; + this.streamId = streamId; + } + + public StreamTextGeneratingMessageContent text(String text) { + this.text = text; + return this; + } + + public StreamTextGeneratingMessageContent streamId(String streamId) { + this.streamId = streamId; + return this; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.StreamingText_Generationg; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Transparent; + } + + @Override + public void decode(MessagePayload payload) { + streamId = payload.getContent(); + text = payload.getSearchableContent(); + } + + @Override + public MessagePayload encode() { + MessagePayload payload = encodeBase(); + payload.setSearchableContent(text); + payload.setContent(streamId); + return payload; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TextMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TextMessageContent.java new file mode 100644 index 00000000..73c99e47 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TextMessageContent.java @@ -0,0 +1,81 @@ +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import cn.wildfirechat.sdk.model.QuoteInfo; +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; + +public class TextMessageContent extends MessageContent { + private String text; + private QuoteInfo quoteInfo; + + //必须有个空的构造函数 + public TextMessageContent() { + } + + public TextMessageContent(String text) { + this.text = text; + } + + public TextMessageContent text(String text) { + this.text = text; + return this; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public QuoteInfo getQuoteInfo() { + return quoteInfo; + } + + public void setQuoteInfo(QuoteInfo quoteInfo) { + this.quoteInfo = quoteInfo; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Text; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = encodeBase(); + payload.setSearchableContent(text); + if(quoteInfo != null) { + payload.setBase64edData(Base64.getEncoder().encodeToString(quoteInfo.encode().toJSONString().getBytes(StandardCharsets.UTF_8))); + } + return payload; + } + + @Override + public void decode(MessagePayload payload) { + text = 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); + quoteInfo = new QuoteInfo(); + quoteInfo.decode(jsonObject); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TipNotificationMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TipNotificationMessageContent.java new file mode 100644 index 00000000..79636d6d --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TipNotificationMessageContent.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; + +public class TipNotificationMessageContent extends MessageContent { + public String tip; + + public TipNotificationMessageContent() { + } + + public String getTip() { + return tip; + } + + public void setTip(String tip) { + this.tip = tip; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setContent(tip); + + return payload; + } + + @Override + public void decode(MessagePayload payload) { + super.decodeBase(payload); + tip = payload.getContent(); + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Tip; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TypingMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TypingMessageContent.java new file mode 100644 index 00000000..46126000 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TypingMessageContent.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; + +public class TypingMessageContent extends MessageContent { + public static final int TYPING_TEXT = 0; + public static final int TYPING_VOICE = 1; + public static final int TYPING_CAMERA = 2; + public static final int TYPING_LOCATION = 3; + public static final int TYPING_FILE = 4; + + private int typingType; + + public TypingMessageContent() { + } + + public TypingMessageContent(int typingType) { + this.typingType = typingType; + } + + public int getTypingType() { + return typingType; + } + + public void setTypingType(int typingType) { + this.typingType = typingType; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Typing; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Transparent; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setContent(typingType + ""); + return payload; + } + + @Override + public void decode(MessagePayload payload) { + super.decodeBase(payload); + typingType = Integer.parseInt(payload.getContent()); + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/UnknownMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/UnknownMessageContent.java new file mode 100644 index 00000000..a9c5a967 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/UnknownMessageContent.java @@ -0,0 +1,32 @@ +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; + +public class UnknownMessageContent extends MessageContent { + private MessagePayload orignalPayload; + + //必须有个空的构造函数 + public UnknownMessageContent() { + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Text; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + return orignalPayload; + } + + @Override + public void decode(MessagePayload payload) { + this.orignalPayload = payload; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/VideoMessageContent.java b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/VideoMessageContent.java new file mode 100644 index 00000000..fe221e81 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/VideoMessageContent.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.messagecontent; + +import cn.wildfirechat.pojos.MessagePayload; +import cn.wildfirechat.proto.ProtoConstants; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.Base64; + + +/** + * Created by heavyrain lee on 2017/12/6. + * + * @refactor dhl + * 添加小视频的宽高,时长 + */ + + +public class VideoMessageContent extends MediaMessageContent { + private byte[] thumbnailBytes; + private long duration ; + + //必须有个空的构造函数 + public VideoMessageContent() { + } + + public VideoMessageContent setThumbnailBytes(byte[] thumbnailBytes) { + this.thumbnailBytes = thumbnailBytes; + return this; + } + + public byte[] getThumbnailBytes() { + return thumbnailBytes; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public long getDuration() { + return duration; + } + + @Override + public int getContentType() { + return ProtoConstants.ContentType.Video; + } + + @Override + public int getPersistFlag() { + return ProtoConstants.PersistFlag.Persist_And_Count; + } + + @Override + public MessagePayload encode() { + MessagePayload payload = super.encodeBase(); + payload.setSearchableContent("[视频]"); + + payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes)); + + JSONObject objWrite = new JSONObject(); + objWrite.put("d", duration); + objWrite.put("duration", duration); + payload.setContent(objWrite.toJSONString()); + + return payload; + } + + @Override + public void decode(MessagePayload payload) { + super.decodeBase(payload); + thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData()); + try { + JSONObject jsonObject = (JSONObject) new JSONParser().parse(payload.getContent()); + if(jsonObject.containsKey("d")) { + duration = (long) jsonObject.get("d"); + } else { + duration = (long) jsonObject.get("duration"); + } + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + @Override + protected int getMediaType() { + return ProtoConstants.MessageMediaType.VIDEO; + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/model/Message.java b/sdk/src/main/java/cn/wildfirechat/sdk/model/Message.java new file mode 100644 index 00000000..fa3d88a5 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/model/Message.java @@ -0,0 +1,15 @@ +package cn.wildfirechat.sdk.model; + +import cn.wildfirechat.pojos.Conversation; +import cn.wildfirechat.sdk.messagecontent.MessageContent; + +import java.util.List; + +public class Message { + public Conversation conversation; + public MessageContent content; + public long messageUid; + public String sender; + public long serverTime; + public List toUsers; +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/model/QuoteInfo.java b/sdk/src/main/java/cn/wildfirechat/sdk/model/QuoteInfo.java new file mode 100644 index 00000000..939bb378 --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/model/QuoteInfo.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 WildFireChat. All rights reserved. + */ + +package cn.wildfirechat.sdk.model; + +import org.json.simple.JSONObject; + +public class QuoteInfo { + private long messageUid; + private String userId; + private String userDisplayName; + private String messageDigest; + + public long getMessageUid() { + return messageUid; + } + + public void setMessageUid(long messageUid) { + this.messageUid = messageUid; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserDisplayName() { + return userDisplayName; + } + + public void setUserDisplayName(String userDisplayName) { + this.userDisplayName = userDisplayName; + } + + public String getMessageDigest() { + return messageDigest; + } + + public void setMessageDigest(String messageDigest) { + this.messageDigest = messageDigest; + } + + public JSONObject encode() { + JSONObject object = new JSONObject(); + object.put("u", messageUid); + object.put("i", userId); + object.put("n", userDisplayName); + object.put("d", messageDigest); + return object; + } + + public void decode(JSONObject object) { + messageUid = (long) object.get("u"); + userId = (String) object.get("i"); + userDisplayName = (String) object.get("n"); + messageDigest = (String) object.get("d"); + } +} diff --git a/sdk/src/main/java/cn/wildfirechat/sdk/utilities/ClassUtil.java b/sdk/src/main/java/cn/wildfirechat/sdk/utilities/ClassUtil.java new file mode 100755 index 00000000..8485851b --- /dev/null +++ b/sdk/src/main/java/cn/wildfirechat/sdk/utilities/ClassUtil.java @@ -0,0 +1,234 @@ +/* + * This file is part of the Wildfire Chat package. + * (c) Heavyrain2012 + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +package cn.wildfirechat.sdk.utilities; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class ClassUtil { + + /** + * 获取同一路径下所有子类或接口实现类 + * + * @param cls + * @return + * @throws IOException + * @throws ClassNotFoundException + */ + public static List> getAllAssignedClass(Class cls) throws IOException, + ClassNotFoundException { + List> classes = new ArrayList>(); + for (Class c : getClasses(cls)) { + if (cls.isAssignableFrom(c) && !cls.equals(c)) { + classes.add(c); + } + } + return classes; + } + + /** + * 取得当前类路径下的所有类 + * + * @param cls + * @return + * @throws IOException + * @throws ClassNotFoundException + */ + public static List> getClasses(Class cls) throws IOException, + ClassNotFoundException { + String pk = cls.getPackage().getName(); +// String path = pk.replace('.', '/'); +// ClassLoader classloader = Thread.currentThread().getContextClassLoader(); +// URL url = classloader.getResource(path); +// String type = url.getProtocol(); +// +// System.out.println("the type is " + type); +// System.out.println(url.getPath()); +// +// return getClasses(new File(url.getFile()), pk); + List classNames = getClassName(pk, true); + List> classes = new ArrayList<>(); + for (String className : + classNames) { + if (className.endsWith(".class")) { + className = className.substring(0, className.length() - 6); + className = className.substring(className.lastIndexOf("/")+1, className.length()); + } + + classes.add(Class.forName(className)); + } + return classes; + } + + /** + * 迭代查找类 + * + * @param dir + * @param pk + * @return + * @throws ClassNotFoundException + */ + private static List> getClasses(File dir, String pk) throws ClassNotFoundException { + System.out.println(dir.getAbsolutePath()); + List> classes = new ArrayList>(); + if (!dir.exists()) { + return classes; + } + for (File f : dir.listFiles()) { + if (f.isDirectory()) { + classes.addAll(getClasses(f, pk + "." + f.getName())); + } + String name = f.getName(); + if (name.endsWith(".class")) { + classes.add(Class.forName(pk + "." + name.substring(0, name.length() - 6))); + } + } + return classes; + } + + + + + /** + * 获取某包下所有类 + * @param packageName 包名 + * @param childPackage 是否遍历子包 + * @return 类的完整名称 + */ + public static List getClassName(String packageName, boolean childPackage) { + List fileNames = null; + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + String packagePath = packageName.replace(".", "/"); + URL url = loader.getResource(packagePath); + if (url != null) { + String type = url.getProtocol(); + if (type.equals("file")) { + fileNames = getClassNameByFile(url.getPath(), null, childPackage); + } else if (type.equals("jar")) { + fileNames = getClassNameByJar(url.getPath(), childPackage); + } + } else { + fileNames = getClassNameByJars(((URLClassLoader) loader).getURLs(), packagePath, childPackage); + } + return fileNames; + } + + /** + * 从项目文件获取某包下所有类 + * @param filePath 文件路径 + * @param className 类名集合 + * @param childPackage 是否遍历子包 + * @return 类的完整名称 + */ + private static List getClassNameByFile(String filePath, List className, boolean childPackage) { + List myClassName = new ArrayList(); + File file = new File(filePath); + File[] childFiles = file.listFiles(); + for (File childFile : childFiles) { + if (childFile.isDirectory()) { + if (childPackage) { + myClassName.addAll(getClassNameByFile(childFile.getPath(), myClassName, childPackage)); + } + } else { + String childFilePath = childFile.getPath(); + if (childFilePath.endsWith(".class")) { + if (childFilePath.indexOf("\\classes") >= 0 || childFilePath.indexOf("/classes") >= 0) { + int start = childFilePath.indexOf("\\classes"); + if (start == -1) { + start = childFilePath.indexOf("/classes"); + } + childFilePath = childFilePath.substring(start + 9, childFilePath.lastIndexOf(".")); + } + childFilePath = childFilePath.replace("\\", "."); + childFilePath = childFilePath.replace("/", "."); + myClassName.add(childFilePath); + } + } + } + + return myClassName; + } + + /** + * 从jar获取某包下所有类 + * @param jarPath jar文件路径 + * @param childPackage 是否遍历子包 + * @return 类的完整名称 + */ + private static List getClassNameByJar(String jarPath, boolean childPackage) { + List myClassName = new ArrayList(); + String[] jarInfo = jarPath.split("!"); + String jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf("/")); + String packagePath = jarInfo[1].substring(1); + try { + JarFile jarFile = new JarFile(jarFilePath); + Enumeration entrys = jarFile.entries(); + while (entrys.hasMoreElements()) { + JarEntry jarEntry = entrys.nextElement(); + String entryName = jarEntry.getName(); + + if (entryName.endsWith(".class")) { + if (childPackage) { + if (entryName.startsWith(packagePath)) { + entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf(".")); + myClassName.add(entryName); + } + } else { + int index = entryName.lastIndexOf("/"); + String myPackagePath; + if (index != -1) { + myPackagePath = entryName.substring(0, index); + } else { + myPackagePath = entryName; + } + if (myPackagePath.equals(packagePath)) { + entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf(".")); + myClassName.add(entryName); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return myClassName; + } + + /** + * 从所有jar中搜索该包,并获取该包下所有类 + * @param urls URL集合 + * @param packagePath 包路径 + * @param childPackage 是否遍历子包 + * @return 类的完整名称 + */ + private static List getClassNameByJars(URL[] urls, String packagePath, boolean childPackage) { + List myClassName = new ArrayList(); + if (urls != null) { + for (int i = 0; i < urls.length; i++) { + URL url = urls[i]; + String urlPath = url.getPath(); + // 不必搜索classes文件夹 + if (urlPath.endsWith("classes/")) { + continue; + } + String jarPath = urlPath + "!/" + packagePath; + myClassName.addAll(getClassNameByJar(jarPath, childPackage)); + } + } + return myClassName; + } + +}