* LCIMMessage.cs:
* LCIMFileMessage.cs: * LCIMTextMessage.cs: * LCIMAudioMessage.cs: * LCIMImageMessage.cs: * LCIMTypedMessage.cs: * LCIMBinaryMessage.cs: * LCIMLocationMessage.cs: * LCIMRecalledMessage.cs: * LCIMMessageController.cs: * LCIMVideoMessage.cs: chore: 重构并支持自定义类型消息
parent
5379ee1285
commit
fb830691c4
|
@ -32,7 +32,7 @@ namespace LeanCloud.Realtime.Internal.Controller {
|
||||||
} else if (message is LCIMBinaryMessage binaryMessage) {
|
} else if (message is LCIMBinaryMessage binaryMessage) {
|
||||||
direct.BinaryMsg = ByteString.CopyFrom(binaryMessage.Data);
|
direct.BinaryMsg = ByteString.CopyFrom(binaryMessage.Data);
|
||||||
} else {
|
} else {
|
||||||
throw new ArgumentException("Message MUST BE LCIMTypedMessage or LCIMBinaryMessage.");
|
throw new ArgumentException("Message MUST be LCIMTypedMessage or LCIMBinaryMessage.");
|
||||||
}
|
}
|
||||||
// 暂态消息
|
// 暂态消息
|
||||||
if (options.Transient) {
|
if (options.Transient) {
|
||||||
|
|
|
@ -2,14 +2,15 @@
|
||||||
using LeanCloud.Storage;
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
|
/// <summary>
|
||||||
|
/// 音频消息
|
||||||
|
/// </summary>
|
||||||
public class LCIMAudioMessage : LCIMFileMessage {
|
public class LCIMAudioMessage : LCIMFileMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// 时长
|
||||||
|
/// </summary>
|
||||||
public double Duration {
|
public double Duration {
|
||||||
get {
|
get; private set;
|
||||||
if (double.TryParse(File.MetaData["duration"] as string, out double duration)) {
|
|
||||||
return duration;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LCIMAudioMessage() {
|
internal LCIMAudioMessage() {
|
||||||
|
@ -21,14 +22,22 @@ namespace LeanCloud.Realtime {
|
||||||
|
|
||||||
internal override Dictionary<string, object> Encode() {
|
internal override Dictionary<string, object> Encode() {
|
||||||
Dictionary<string, object> data = base.Encode();
|
Dictionary<string, object> data = base.Encode();
|
||||||
Dictionary<string, object> fileData = data["_lcfile"] as Dictionary<string, object>;
|
Dictionary<string, object> fileData = data[MessageFileKey] as Dictionary<string, object>;
|
||||||
Dictionary<string, object> metaData = fileData["metaData"] as Dictionary<string, object>;
|
Dictionary<string, object> metaData = fileData[MessageDataMetaDataKey] as Dictionary<string, object>;
|
||||||
if (File.MetaData.TryGetValue("duration", out object duration)) {
|
if (File.MetaData.TryGetValue(MessageDataMetaDurationKey, out object duration)) {
|
||||||
metaData["duration"] = duration;
|
metaData[MessageDataMetaDurationKey] = duration;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override int MessageType => AudioMessageType;
|
internal override void Decode(Dictionary<string, object> msgData) {
|
||||||
|
base.Decode(msgData);
|
||||||
|
if (File.MetaData.TryGetValue(MessageDataMetaDurationKey, out object duration) &&
|
||||||
|
double.TryParse(duration as string, out double d)) {
|
||||||
|
Duration = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int MessageType => AudioMessageType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
|
/// <summary>
|
||||||
|
/// 二进制消息
|
||||||
|
/// </summary>
|
||||||
public class LCIMBinaryMessage : LCIMMessage {
|
public class LCIMBinaryMessage : LCIMMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// 消息数据
|
||||||
|
/// </summary>
|
||||||
public byte[] Data {
|
public byte[] Data {
|
||||||
get; internal set;
|
get; internal set;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,29 +3,41 @@ using System.Collections.Generic;
|
||||||
using LeanCloud.Storage;
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
|
/// <summary>
|
||||||
|
/// 文件消息
|
||||||
|
/// </summary>
|
||||||
public class LCIMFileMessage : LCIMTextMessage {
|
public class LCIMFileMessage : LCIMTextMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// 文件
|
||||||
|
/// </summary>
|
||||||
public LCFile File {
|
public LCFile File {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件大小
|
||||||
|
/// </summary>
|
||||||
public int Size {
|
public int Size {
|
||||||
get {
|
get {
|
||||||
if (int.TryParse(File.MetaData["size"] as string, out int size)) {
|
if (int.TryParse(File.MetaData[MessageDataMetaSizeKey] as string, out int size)) {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件类型
|
||||||
|
/// </summary>
|
||||||
public string Format {
|
public string Format {
|
||||||
get {
|
get {
|
||||||
if (File.MetaData.TryGetValue("format", out object format)) {
|
return File.MimeType;
|
||||||
return format as string;
|
|
||||||
}
|
|
||||||
return "unknown/unknown";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件链接
|
||||||
|
/// </summary>
|
||||||
public string Url {
|
public string Url {
|
||||||
get {
|
get {
|
||||||
return File.Url;
|
return File.Url;
|
||||||
|
@ -40,43 +52,48 @@ namespace LeanCloud.Realtime {
|
||||||
File = file;
|
File = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override int MessageType => FileMessageType;
|
public override int MessageType => FileMessageType;
|
||||||
|
|
||||||
internal override Dictionary<string, object> Encode() {
|
internal override Dictionary<string, object> Encode() {
|
||||||
if (File == null) {
|
if (File == null) {
|
||||||
throw new Exception("File MUST NOT be null before sent.");
|
throw new Exception("File MUST NOT be null before sent.");
|
||||||
}
|
}
|
||||||
Dictionary<string, object> fileData = new Dictionary<string, object> {
|
Dictionary<string, object> fileData = new Dictionary<string, object> {
|
||||||
{ "objId", File.ObjectId },
|
{ MessageDataObjectIdKey, File.ObjectId },
|
||||||
{ "url", File.Url },
|
{ MessageDataUrlKey, File.Url },
|
||||||
{ "metaData", new Dictionary<string, object> {
|
{ MessageDataMetaDataKey, new Dictionary<string, object> {
|
||||||
{ "name", File.Name },
|
{ MessageDataMetaNameKey, File.Name },
|
||||||
{ "format", File.MimeType }
|
{ MessageDataMetaFormatKey, File.MimeType }
|
||||||
} }
|
} }
|
||||||
};
|
};
|
||||||
if (File.MetaData.TryGetValue("size", out object size)) {
|
if (File.MetaData.TryGetValue(MessageDataMetaSizeKey, out object size)) {
|
||||||
Dictionary<string, object> metaData = fileData["metaData"] as Dictionary<string, object>;
|
Dictionary<string, object> metaData = fileData[MessageDataMetaDataKey] as Dictionary<string, object>;
|
||||||
metaData["size"] = size;
|
metaData[MessageDataMetaSizeKey] = size;
|
||||||
}
|
}
|
||||||
Dictionary<string, object> data = base.Encode();
|
Dictionary<string, object> data = base.Encode();
|
||||||
data["_lcfile"] = fileData;
|
data[MessageFileKey] = fileData;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DecodeMessageData(Dictionary<string, object> msgData) {
|
internal override void Decode(Dictionary<string, object> msgData) {
|
||||||
base.DecodeMessageData(msgData);
|
base.Decode(msgData);
|
||||||
Dictionary<string, object> fileData = msgData["_lcfile"] as Dictionary<string, object>;
|
|
||||||
string objectId = fileData["objId"] as string;
|
if (msgData.TryGetValue(MessageFileKey, out object fileDataObject)) {
|
||||||
|
Dictionary<string, object> fileData = fileDataObject as Dictionary<string, object>;
|
||||||
|
if (fileData.TryGetValue(MessageDataObjectIdKey, out object objectIdObject)) {
|
||||||
|
string objectId = objectIdObject as string;
|
||||||
File = LCObject.CreateWithoutData(LCFile.CLASS_NAME, objectId) as LCFile;
|
File = LCObject.CreateWithoutData(LCFile.CLASS_NAME, objectId) as LCFile;
|
||||||
if (fileData.TryGetValue("url", out object url)) {
|
if (fileData.TryGetValue(MessageDataUrlKey, out object url)) {
|
||||||
File.Url = url as string;
|
File.Url = url as string;
|
||||||
}
|
}
|
||||||
if (fileData.TryGetValue("metaData", out object metaData)) {
|
if (fileData.TryGetValue(MessageDataMetaDataKey, out object metaData)) {
|
||||||
File.MetaData = metaData as Dictionary<string, object>;
|
File.MetaData = metaData as Dictionary<string, object>;
|
||||||
if (File.MetaData.TryGetValue("name", out object name)) {
|
if (File.MetaData.TryGetValue(MessageDataMetaNameKey, out object name)) {
|
||||||
File.Name = name as string;
|
File.Name = name as string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,22 @@
|
||||||
using LeanCloud.Storage;
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
|
/// <summary>
|
||||||
|
/// 图像消息
|
||||||
|
/// </summary>
|
||||||
public class LCIMImageMessage : LCIMFileMessage {
|
public class LCIMImageMessage : LCIMFileMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// 图像宽度
|
||||||
|
/// </summary>
|
||||||
public int Width {
|
public int Width {
|
||||||
get {
|
get; private set;
|
||||||
if (int.TryParse(File.MetaData["width"] as string, out int width)) {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图像高度
|
||||||
|
/// </summary>
|
||||||
public int Height {
|
public int Height {
|
||||||
get {
|
get; private set;
|
||||||
if (int.TryParse(File.MetaData["height"] as string, out int height)) {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LCIMImageMessage() : base() {
|
internal LCIMImageMessage() : base() {
|
||||||
|
@ -30,17 +29,29 @@ namespace LeanCloud.Realtime {
|
||||||
|
|
||||||
internal override Dictionary<string, object> Encode() {
|
internal override Dictionary<string, object> Encode() {
|
||||||
Dictionary<string, object> data = base.Encode();
|
Dictionary<string, object> data = base.Encode();
|
||||||
Dictionary<string, object> fileData = data["_lcfile"] as Dictionary<string, object>;
|
Dictionary<string, object> fileData = data[MessageFileKey] as Dictionary<string, object>;
|
||||||
Dictionary<string, object> metaData = fileData["metaData"] as Dictionary<string, object>;
|
Dictionary<string, object> metaData = fileData[MessageDataMetaDataKey] as Dictionary<string, object>;
|
||||||
if (File.MetaData.TryGetValue("width", out object width)) {
|
if (File.MetaData.TryGetValue(MessageDataMetaWidthKey, out object width)) {
|
||||||
metaData["width"] = width;
|
metaData[MessageDataMetaWidthKey] = width;
|
||||||
}
|
}
|
||||||
if (File.MetaData.TryGetValue("height", out object height)) {
|
if (File.MetaData.TryGetValue(MessageDataMetaHeightKey, out object height)) {
|
||||||
metaData["height"] = height;
|
metaData[MessageDataMetaHeightKey] = height;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override int MessageType => ImageMessageType;
|
internal override void Decode(Dictionary<string, object> msgData) {
|
||||||
|
base.Decode(msgData);
|
||||||
|
if (File.MetaData.TryGetValue(MessageDataMetaWidthKey, out object width) &&
|
||||||
|
int.TryParse(width as string, out int w)) {
|
||||||
|
Width = w;
|
||||||
|
}
|
||||||
|
if (File.MetaData.TryGetValue(MessageDataMetaHeightKey, out object height) &&
|
||||||
|
int.TryParse(height as string, out int h)) {
|
||||||
|
Height = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int MessageType => ImageMessageType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,13 @@
|
||||||
using LeanCloud.Storage;
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
|
/// <summary>
|
||||||
|
/// 位置消息
|
||||||
|
/// </summary>
|
||||||
public class LCIMLocationMessage : LCIMTextMessage {
|
public class LCIMLocationMessage : LCIMTextMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// 位置
|
||||||
|
/// </summary>
|
||||||
public LCGeoPoint Location {
|
public LCGeoPoint Location {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
@ -17,19 +23,30 @@ namespace LeanCloud.Realtime {
|
||||||
internal override Dictionary<string, object> Encode() {
|
internal override Dictionary<string, object> Encode() {
|
||||||
Dictionary<string, object> data = base.Encode();
|
Dictionary<string, object> data = base.Encode();
|
||||||
Dictionary<string, object> locationData = new Dictionary<string, object> {
|
Dictionary<string, object> locationData = new Dictionary<string, object> {
|
||||||
{ "longitude", Location.Longitude },
|
{ MessageDataLongitudeKey, Location.Longitude },
|
||||||
{ "latitude", Location.Latitude }
|
{ MessageDataLatitudeKey, Location.Latitude }
|
||||||
};
|
};
|
||||||
data["_lcloc"] = locationData;
|
data[MessageLocationKey] = locationData;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DecodeMessageData(Dictionary<string, object> msgData) {
|
internal override void Decode(Dictionary<string, object> msgData) {
|
||||||
base.DecodeMessageData(msgData);
|
base.Decode(msgData);
|
||||||
Dictionary<string, object> locationData = msgData["_lcloc"] as Dictionary<string, object>;
|
if (msgData.TryGetValue(MessageLocationKey, out object val)) {
|
||||||
Location = new LCGeoPoint((double)locationData["latitude"], (double)locationData["longitude"]);
|
Dictionary<string, object> locationData = val as Dictionary<string, object>;
|
||||||
|
double latitude = 0, longitude = 0;
|
||||||
|
if (locationData.TryGetValue(MessageDataLatitudeKey, out object lat) &&
|
||||||
|
double.TryParse(lat as string, out double la)) {
|
||||||
|
latitude = la;
|
||||||
|
}
|
||||||
|
if (locationData.TryGetValue(MessageDataLongitudeKey, out object lon) &&
|
||||||
|
double.TryParse(lon as string, out double lo)) {
|
||||||
|
longitude = lo;
|
||||||
|
}
|
||||||
|
Location = new LCGeoPoint(latitude, longitude);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override int MessageType => LocationMessageType;
|
public override int MessageType => LocationMessageType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,31 +2,41 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
|
/// <summary>
|
||||||
|
/// 消息基类
|
||||||
|
/// </summary>
|
||||||
public abstract class LCIMMessage {
|
public abstract class LCIMMessage {
|
||||||
internal const int TextMessageType = -1;
|
/// <summary>
|
||||||
internal const int ImageMessageType = -2;
|
/// 消息所在对话 Id
|
||||||
internal const int AudioMessageType = -3;
|
/// </summary>
|
||||||
internal const int VideoMessageType = -4;
|
|
||||||
internal const int LocationMessageType = -5;
|
|
||||||
internal const int FileMessageType = -6;
|
|
||||||
internal const int RecalledMessageType = -127;
|
|
||||||
|
|
||||||
public string ConversationId {
|
public string ConversationId {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消息 Id
|
||||||
|
/// </summary>
|
||||||
public string Id {
|
public string Id {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送者 Id
|
||||||
|
/// </summary>
|
||||||
public string FromClientId {
|
public string FromClientId {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送时间戳
|
||||||
|
/// </summary>
|
||||||
public long SentTimestamp {
|
public long SentTimestamp {
|
||||||
get; internal set;
|
get; internal set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送时间
|
||||||
|
/// </summary>
|
||||||
public DateTime SentAt {
|
public DateTime SentAt {
|
||||||
get {
|
get {
|
||||||
return DateTimeOffset.FromUnixTimeMilliseconds(SentTimestamp)
|
return DateTimeOffset.FromUnixTimeMilliseconds(SentTimestamp)
|
||||||
|
@ -34,10 +44,16 @@ namespace LeanCloud.Realtime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 送达时间戳
|
||||||
|
/// </summary>
|
||||||
public long DeliveredTimestamp {
|
public long DeliveredTimestamp {
|
||||||
get; internal set;
|
get; internal set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 送达时间
|
||||||
|
/// </summary>
|
||||||
public DateTime DeliveredAt {
|
public DateTime DeliveredAt {
|
||||||
get {
|
get {
|
||||||
return DateTimeOffset.FromUnixTimeMilliseconds(DeliveredTimestamp)
|
return DateTimeOffset.FromUnixTimeMilliseconds(DeliveredTimestamp)
|
||||||
|
@ -45,10 +61,16 @@ namespace LeanCloud.Realtime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已读时间戳
|
||||||
|
/// </summary>
|
||||||
public long ReadTimestamp {
|
public long ReadTimestamp {
|
||||||
get; internal set;
|
get; internal set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已读时间
|
||||||
|
/// </summary>
|
||||||
public DateTime ReadAt {
|
public DateTime ReadAt {
|
||||||
get {
|
get {
|
||||||
return DateTimeOffset.FromUnixTimeMilliseconds(ReadTimestamp)
|
return DateTimeOffset.FromUnixTimeMilliseconds(ReadTimestamp)
|
||||||
|
@ -56,10 +78,16 @@ namespace LeanCloud.Realtime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 修改时间戳
|
||||||
|
/// </summary>
|
||||||
public long PatchedTimestamp {
|
public long PatchedTimestamp {
|
||||||
get; internal set;
|
get; internal set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 修改时间
|
||||||
|
/// </summary>
|
||||||
public DateTime PatchedAt {
|
public DateTime PatchedAt {
|
||||||
get {
|
get {
|
||||||
return DateTimeOffset.FromUnixTimeMilliseconds(PatchedTimestamp)
|
return DateTimeOffset.FromUnixTimeMilliseconds(PatchedTimestamp)
|
||||||
|
@ -67,18 +95,30 @@ namespace LeanCloud.Realtime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提醒成员 Id 列表
|
||||||
|
/// </summary>
|
||||||
public List<string> MentionIdList {
|
public List<string> MentionIdList {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否提醒所有人
|
||||||
|
/// </summary>
|
||||||
public bool MentionAll {
|
public bool MentionAll {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否提醒当前用户
|
||||||
|
/// </summary>
|
||||||
public bool Mentioned {
|
public bool Mentioned {
|
||||||
get; internal set;
|
get; internal set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是暂态消息
|
||||||
|
/// </summary>
|
||||||
public bool IsTransient {
|
public bool IsTransient {
|
||||||
get; internal set;
|
get; internal set;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,6 @@ namespace LeanCloud.Realtime {
|
||||||
public LCIMRecalledMessage() {
|
public LCIMRecalledMessage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override int MessageType => RecalledMessageType;
|
public override int MessageType => RecalledMessageType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
|
/// <summary>
|
||||||
|
/// 文本消息
|
||||||
|
/// </summary>
|
||||||
public class LCIMTextMessage : LCIMTypedMessage {
|
public class LCIMTextMessage : LCIMTypedMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// 文本
|
||||||
|
/// </summary>
|
||||||
public string Text {
|
public string Text {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
@ -16,16 +22,16 @@ namespace LeanCloud.Realtime {
|
||||||
internal override Dictionary<string, object> Encode() {
|
internal override Dictionary<string, object> Encode() {
|
||||||
Dictionary<string, object> data = base.Encode();
|
Dictionary<string, object> data = base.Encode();
|
||||||
if (!string.IsNullOrEmpty(Text)) {
|
if (!string.IsNullOrEmpty(Text)) {
|
||||||
data["_lctext"] = Text;
|
data[MessageTextKey] = Text;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override int MessageType => TextMessageType;
|
public override int MessageType => TextMessageType;
|
||||||
|
|
||||||
protected override void DecodeMessageData(Dictionary<string, object> msgData) {
|
internal override void Decode(Dictionary<string, object> msgData) {
|
||||||
base.DecodeMessageData(msgData);
|
base.Decode(msgData);
|
||||||
if (msgData.TryGetValue("_lctext", out object value)) {
|
if (msgData.TryGetValue(MessageTextKey, out object value)) {
|
||||||
Text = value as string;
|
Text = value as string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,85 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using LeanCloud.Storage.Internal.Codec;
|
using LeanCloud.Storage.Internal.Codec;
|
||||||
using LeanCloud.Storage.Internal;
|
using LeanCloud.Storage.Internal;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
public abstract class LCIMTypedMessage : LCIMMessage {
|
/// <summary>
|
||||||
|
/// 已知类型消息
|
||||||
|
/// </summary>
|
||||||
|
public class LCIMTypedMessage : LCIMMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// 文本消息
|
||||||
|
/// </summary>
|
||||||
|
public const int TextMessageType = -1;
|
||||||
|
/// <summary>
|
||||||
|
/// 图像消息
|
||||||
|
/// </summary>
|
||||||
|
public const int ImageMessageType = -2;
|
||||||
|
/// <summary>
|
||||||
|
/// 音频消息
|
||||||
|
/// </summary>
|
||||||
|
public const int AudioMessageType = -3;
|
||||||
|
/// <summary>
|
||||||
|
/// 视频消息
|
||||||
|
/// </summary>
|
||||||
|
public const int VideoMessageType = -4;
|
||||||
|
/// <summary>
|
||||||
|
/// 位置消息
|
||||||
|
/// </summary>
|
||||||
|
public const int LocationMessageType = -5;
|
||||||
|
/// <summary>
|
||||||
|
/// 文件消息
|
||||||
|
/// </summary>
|
||||||
|
public const int FileMessageType = -6;
|
||||||
|
/// <summary>
|
||||||
|
/// 撤回消息
|
||||||
|
/// </summary>
|
||||||
|
public const int RecalledMessageType = -127;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保留字段
|
||||||
|
/// </summary>
|
||||||
|
protected const string MessageTypeKey = "_lctype";
|
||||||
|
protected const string MessageAttributesKey = "_lcattrs";
|
||||||
|
protected const string MessageTextKey = "_lctext";
|
||||||
|
protected const string MessageLocationKey = "_lcloc";
|
||||||
|
protected const string MessageFileKey = "_lcfile";
|
||||||
|
|
||||||
|
protected const string MessageDataLongitudeKey = "longitude";
|
||||||
|
protected const string MessageDataLatitudeKey = "latitude";
|
||||||
|
|
||||||
|
protected const string MessageDataObjectIdKey = "objId";
|
||||||
|
protected const string MessageDataUrlKey = "url";
|
||||||
|
protected const string MessageDataMetaDataKey = "metaData";
|
||||||
|
protected const string MessageDataMetaNameKey = "name";
|
||||||
|
protected const string MessageDataMetaFormatKey = "format";
|
||||||
|
protected const string MessageDataMetaSizeKey = "size";
|
||||||
|
protected const string MessageDataMetaWidthKey = "width";
|
||||||
|
protected const string MessageDataMetaHeightKey = "height";
|
||||||
|
protected const string MessageDataMetaDurationKey = "duration";
|
||||||
|
|
||||||
|
|
||||||
private Dictionary<string, object> customProperties;
|
private Dictionary<string, object> customProperties;
|
||||||
|
|
||||||
internal virtual int MessageType {
|
/// <summary>
|
||||||
|
/// 完整的消息数据
|
||||||
|
/// </summary>
|
||||||
|
protected Dictionary<string, object> data = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消息类型
|
||||||
|
/// </summary>
|
||||||
|
public virtual int MessageType {
|
||||||
get; private set;
|
get; private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消息属性访问
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public object this[string key] {
|
public object this[string key] {
|
||||||
get {
|
get {
|
||||||
if (customProperties == null) {
|
if (customProperties == null) {
|
||||||
|
@ -30,18 +99,19 @@ namespace LeanCloud.Realtime {
|
||||||
}
|
}
|
||||||
|
|
||||||
internal virtual Dictionary<string, object> Encode() {
|
internal virtual Dictionary<string, object> Encode() {
|
||||||
Dictionary<string, object> msgData = new Dictionary<string, object> {
|
Dictionary<string, object> msgData = data != null ?
|
||||||
{ "_lctype", MessageType }
|
new Dictionary<string, object>(data) : new Dictionary<string, object>();
|
||||||
};
|
msgData[MessageTypeKey] = MessageType;
|
||||||
if (customProperties != null && customProperties.Count > 0) {
|
if (customProperties != null && customProperties.Count > 0) {
|
||||||
msgData["_lcattrs"] = LCEncoder.Encode(customProperties);
|
msgData[MessageAttributesKey] = LCEncoder.Encode(customProperties);
|
||||||
}
|
}
|
||||||
return msgData;
|
return msgData;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void DecodeMessageData(Dictionary<string, object> msgData) {
|
internal virtual void Decode(Dictionary<string, object> msgData) {
|
||||||
MessageType = (int)msgData["_lctype"];
|
data = msgData;
|
||||||
if (msgData.TryGetValue("_lcattrs", out object attrObj)) {
|
MessageType = (int)msgData[MessageTypeKey];
|
||||||
|
if (msgData.TryGetValue(MessageAttributesKey, out object attrObj)) {
|
||||||
customProperties = LCDecoder.Decode(attrObj) as Dictionary<string, object>;
|
customProperties = LCDecoder.Decode(attrObj) as Dictionary<string, object>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,36 +120,38 @@ namespace LeanCloud.Realtime {
|
||||||
Dictionary<string, object> msgData = JsonConvert.DeserializeObject<Dictionary<string, object>>(json,
|
Dictionary<string, object> msgData = JsonConvert.DeserializeObject<Dictionary<string, object>>(json,
|
||||||
new LCJsonConverter());
|
new LCJsonConverter());
|
||||||
LCIMTypedMessage message = null;
|
LCIMTypedMessage message = null;
|
||||||
int msgType = (int)msgData["_lctype"];
|
int msgType = (int)msgData[MessageTypeKey];
|
||||||
switch (msgType) {
|
if (customMessageDict.TryGetValue(msgType, out Func<LCIMTypedMessage> msgConstructor)) {
|
||||||
case TextMessageType:
|
// 已注册的类型消息
|
||||||
message = new LCIMTextMessage();
|
message = msgConstructor.Invoke();
|
||||||
break;
|
} else {
|
||||||
case ImageMessageType:
|
// 未注册的类型消息
|
||||||
message = new LCIMImageMessage();
|
message = new LCIMTypedMessage();
|
||||||
break;
|
|
||||||
case AudioMessageType:
|
|
||||||
message = new LCIMAudioMessage();
|
|
||||||
break;
|
|
||||||
case VideoMessageType:
|
|
||||||
message = new LCIMVideoMessage();
|
|
||||||
break;
|
|
||||||
case LocationMessageType:
|
|
||||||
message = new LCIMLocationMessage();
|
|
||||||
break;
|
|
||||||
case FileMessageType:
|
|
||||||
message = new LCIMFileMessage();
|
|
||||||
break;
|
|
||||||
case RecalledMessageType:
|
|
||||||
message = new LCIMRecalledMessage();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// TODO 用户自定义类型消息
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
message.DecodeMessageData(msgData);
|
message.Decode(msgData);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 内置已知类型消息
|
||||||
|
static readonly Dictionary<int, Func<LCIMTypedMessage>> customMessageDict = new Dictionary<int, Func<LCIMTypedMessage>> {
|
||||||
|
{ TextMessageType, () => new LCIMTextMessage() },
|
||||||
|
{ ImageMessageType, () => new LCIMImageMessage() },
|
||||||
|
{ AudioMessageType, () => new LCIMAudioMessage() },
|
||||||
|
{ VideoMessageType, () => new LCIMVideoMessage() },
|
||||||
|
{ LocationMessageType, () => new LCIMLocationMessage() },
|
||||||
|
{ FileMessageType, () => new LCIMFileMessage() },
|
||||||
|
{ RecalledMessageType, () => new LCIMRecalledMessage() }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册自定义类型消息
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="msgType"></param>
|
||||||
|
/// <param name="msgConstructor"></param>
|
||||||
|
public static void Register<T>(int msgType, Func<T> msgConstructor)
|
||||||
|
where T : LCIMTypedMessage {
|
||||||
|
customMessageDict[msgType] = msgConstructor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,29 @@
|
||||||
using LeanCloud.Storage;
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
|
/// <summary>
|
||||||
|
/// 视频消息
|
||||||
|
/// </summary>
|
||||||
public class LCIMVideoMessage : LCIMFileMessage {
|
public class LCIMVideoMessage : LCIMFileMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// 宽度
|
||||||
|
/// </summary>
|
||||||
|
public int Width {
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 高度
|
||||||
|
/// </summary>
|
||||||
|
public int Height {
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 时长
|
||||||
|
/// </summary>
|
||||||
public double Duration {
|
public double Duration {
|
||||||
get {
|
get; private set;
|
||||||
if (double.TryParse(File.MetaData["duration"] as string, out double duration)) {
|
|
||||||
return duration;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LCIMVideoMessage() {
|
internal LCIMVideoMessage() {
|
||||||
|
@ -21,20 +36,36 @@ namespace LeanCloud.Realtime {
|
||||||
|
|
||||||
internal override Dictionary<string, object> Encode() {
|
internal override Dictionary<string, object> Encode() {
|
||||||
Dictionary<string, object> data = base.Encode();
|
Dictionary<string, object> data = base.Encode();
|
||||||
Dictionary<string, object> fileData = data["_lcfile"] as Dictionary<string, object>;
|
Dictionary<string, object> fileData = data[MessageFileKey] as Dictionary<string, object>;
|
||||||
Dictionary<string, object> metaData = fileData["metaData"] as Dictionary<string, object>;
|
Dictionary<string, object> metaData = fileData[MessageDataMetaDataKey] as Dictionary<string, object>;
|
||||||
if (File.MetaData.TryGetValue("width", out object width)) {
|
if (File.MetaData.TryGetValue(MessageDataMetaWidthKey, out object width)) {
|
||||||
metaData["width"] = width;
|
metaData[MessageDataMetaWidthKey] = width;
|
||||||
}
|
}
|
||||||
if (File.MetaData.TryGetValue("height", out object height)) {
|
if (File.MetaData.TryGetValue(MessageDataMetaHeightKey, out object height)) {
|
||||||
metaData["height"] = height;
|
metaData[MessageDataMetaHeightKey] = height;
|
||||||
}
|
}
|
||||||
if (File.MetaData.TryGetValue("duration", out object duration)) {
|
if (File.MetaData.TryGetValue(MessageDataMetaDurationKey, out object duration)) {
|
||||||
metaData["duration"] = duration;
|
metaData[MessageDataMetaDurationKey] = duration;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override int MessageType => VideoMessageType;
|
internal override void Decode(Dictionary<string, object> msgData) {
|
||||||
|
base.Decode(msgData);
|
||||||
|
if (File.MetaData.TryGetValue(MessageDataMetaWidthKey, out object width) &&
|
||||||
|
int.TryParse(width as string, out int w)) {
|
||||||
|
Width = w;
|
||||||
|
}
|
||||||
|
if (File.MetaData.TryGetValue(MessageDataMetaHeightKey, out object height) &&
|
||||||
|
int.TryParse(height as string, out int h)) {
|
||||||
|
Height = h;
|
||||||
|
}
|
||||||
|
if (File.MetaData.TryGetValue(MessageDataMetaDurationKey, out object duration) &&
|
||||||
|
double.TryParse(duration as string, out double d)) {
|
||||||
|
Duration = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int MessageType => VideoMessageType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue