/// <summary> /// 当前用户对目标对话进行静音操作 /// </summary> /// <param name="conversation"></param> /// <returns></returns> public Task MuteConversationAsync(AVIMConversation conversation) { var convCmd = new ConversationCommand() .ConversationId(conversation.ConversationId) .Option("mute") .PeerId(this.ClientId); return(this.RunCommandAsync(convCmd)); }
/// <summary> /// 创建聊天室(即:暂态对话) /// </summary> /// <param name="chatroomName">聊天室名称</param> /// <returns></returns> public Task <AVIMConversation> CreateChatRoomAsync(string chatroomName) { var conversation = new AVIMConversation() { Name = chatroomName, IsTransient = true }; return(CreateConversationAsync(conversation)); }
/// <summary> /// 当前用户对目标对话取消静音,恢复该对话的离线消息推送 /// </summary> /// <param name="conversation"></param> /// <returns></returns> public Task UnmuteConversationAsync(AVIMConversation conversation) { var convCmd = new ConversationCommand() .ConversationId(conversation.ConversationId) .Option("unmute") .PeerId(this.ClientId); return(this.LinkedRealtime.AVIMCommandRunner.RunCommandAsync(convCmd)); }
/// <summary> /// AVIMConversation Build 驱动器 /// </summary> /// <param name="source"></param> /// <param name="name"></param> /// <param name="creator"></param> /// <param name="members"></param> /// <param name="muteMembers"></param> /// <param name="isTransient"></param> /// <param name="isSystem"></param> /// <param name="attributes"></param> /// <param name="state"></param> /// <param name="isUnique"></param> internal AVIMConversation(AVIMConversation source = null, string name = null, string creator = null, IEnumerable <string> members = null, IEnumerable <string> muteMembers = null, bool isTransient = false, bool isSystem = false, IEnumerable <KeyValuePair <string, object> > attributes = null, AVObject state = null, bool isUnique = true) { convState = source != null ? source.convState : new AVObject("_Conversation"); this.Name = source?.Name; this.MemberIds = source?.MemberIds; this.Creator = source?.Creator; this.MuteMemberIds = source?.MuteMemberIds; if (!string.IsNullOrEmpty(name)) { this.Name = name; } if (!string.IsNullOrEmpty(creator)) { this.Creator = creator; } if (members != null) { this.MemberIds = members.ToList(); } if (muteMembers != null) { this.MuteMemberIds = muteMembers.ToList(); } this.IsTransient = isTransient; this.IsSystem = isSystem; this.IsUnique = isUnique; if (state != null) { convState = state; this.ConversationId = state.ObjectId; this.CreatedAt = state.CreatedAt; this.UpdatedAt = state.UpdatedAt; this.MergeMagicFields(state.ToDictionary(x => x.Key, x => x.Value)); } if (attributes != null) { this.MergeMagicFields(attributes.ToDictionary(x => x.Key, x => x.Value)); } }
/// <summary> /// 向目标对话发送消息 /// </summary> /// <param name="conversation">目标对话</param> /// <param name="message">消息体</param> /// <returns></returns> public Task <IAVIMMessage> SendMessageAsync( AVIMConversation conversation, IAVIMMessage message) { return(this.SendMessageAsync(conversation, message, new AVIMSendOptions() { Receipt = true, Transient = false, Priority = 1, Will = false, PushData = null, })); }
/// <summary> /// 查询目标对话的历史消息 /// <remarks>不支持聊天室(暂态对话)</remarks> /// </summary> /// <param name="conversation">目标对话</param> /// <param name="beforeMessageId">从 beforeMessageId 开始向前查询(和 beforeTimeStampPoint 共同使用,为防止某毫秒时刻有重复消息)</param> /// <param name="afterMessageId"> 截止到某个 afterMessageId (不包含)</param> /// <param name="beforeTimeStampPoint">从 beforeTimeStampPoint 开始向前查询</param> /// <param name="afterTimeStampPoint">拉取截止到 afterTimeStampPoint 时间戳(不包含)</param> /// <param name="limit">拉取消息条数,默认值 20 条,可设置为 1 - 1000 之间的任意整数</param> /// <returns></returns> public Task <IEnumerable <IAVIMMessage> > QueryMessageAsync(AVIMConversation conversation, string beforeMessageId = null, string afterMessageId = null, DateTime?beforeTimeStampPoint = null, DateTime?afterTimeStampPoint = null, int limit = 20) { var logsCmd = new AVIMCommand() .Command("logs") .Argument("cid", conversation.ConversationId) .Argument("l", limit); if (beforeMessageId != null) { logsCmd = logsCmd.Argument("mid", beforeMessageId); } if (afterMessageId != null) { logsCmd = logsCmd.Argument("tmid", afterMessageId); } if (beforeTimeStampPoint != null) { logsCmd = logsCmd.Argument("t", beforeTimeStampPoint.Value.UnixTimeStampSeconds()); } if (afterTimeStampPoint != null) { logsCmd = logsCmd.Argument("tt", afterTimeStampPoint.Value.UnixTimeStampSeconds()); } return(this.LinkedRealtime.AVIMCommandRunner.RunCommandAsync(logsCmd).OnSuccess(t => { var rtn = new List <IAVIMMessage>(); var result = t.Result.Item2; var logs = result["logs"] as List <object>; if (logs != null) { foreach (var log in logs) { var logMap = log as IDictionary <string, object>; if (logMap != null) { var msgStr = logMap["data"].ToString(); var messageObj = AVRealtime.FreeStyleMessageClassingController.Instantiate(msgStr, logMap); messageObj.ConversationId = conversation.ConversationId; rtn.Add(messageObj); } } } return rtn.AsEnumerable(); })); }
/// <summary> /// 向目标对话发送消息 /// </summary> /// <param name="conversation">目标对话</param> /// <param name="message">消息体</param> /// <param name="options">消息的发送选项,包含了一些特殊的标记<see cref="AVIMSendOptions"/></param> /// <returns></returns> public Task <IAVIMMessage> SendMessageAsync( AVIMConversation conversation, IAVIMMessage message, AVIMSendOptions options) { if (this.LinkedRealtime.State != AVRealtime.Status.Online) { throw new Exception("未能连接到服务器,无法发送消息。"); } var messageBody = message.Serialize(); message.ConversationId = conversation.ConversationId; message.FromClientId = this.ClientId; var cmd = new MessageCommand() .Message(messageBody) .ConvId(conversation.ConversationId) .Receipt(options.Receipt) .Transient(options.Transient) .Priority(options.Priority) .Will(options.Will) .MentionAll(message.MentionAll); if (message is AVIMMessage) { cmd = ((AVIMMessage)message).BeforeSend(cmd); } if (options.PushData != null) { cmd = cmd.PushData(options.PushData); } if (message.MentionList != null) { cmd = cmd.Mention(message.MentionList); } var directCmd = cmd.PeerId(this.ClientId); return(this.RunCommandAsync(directCmd).OnSuccess(t => { var response = t.Result.Item2; message.Id = response["uid"].ToString(); message.ServerTimestamp = long.Parse(response["t"].ToString()); return message; })); }
/// <summary> /// Query messages. /// </summary> /// <returns>The message async.</returns> /// <param name="client">Client.</param> /// <param name="conversation">Conversation.</param> /// <param name="beforeMessageId">Before message identifier.</param> /// <param name="afterMessageId">After message identifier.</param> /// <param name="beforeTimeStampPoint">Before time stamp point.</param> /// <param name="afterTimeStampPoint">After time stamp point.</param> /// <param name="direction">Direction.</param> /// <param name="limit">Limit.</param> public static Task <IEnumerable <IAVIMMessage> > QueryMessageAsync(this AVIMClient client, AVIMConversation conversation, string beforeMessageId = null, string afterMessageId = null, DateTime?beforeTimeStampPoint = null, DateTime?afterTimeStampPoint = null, int direction = 1, int limit = 20) { return(client.QueryMessageAsync <IAVIMMessage>(conversation, beforeMessageId, afterMessageId, beforeTimeStampPoint, afterTimeStampPoint, direction, limit)); }
/// <summary> /// 向目标对话发送消息 /// </summary> /// <param name="conversation">目标对话</param> /// <param name="message">消息体</param> /// <param name="receipt">是否需要送达回执</param> /// <param name="transient">是否是暂态消息,暂态消息不返回送达回执(ack),不保留离线消息,不触发离线推送</param> /// <param name="priority">消息等级,默认是1,可选值还有 2 ,3</param> /// <param name="will">标记该消息是否为下线通知消息</param> /// <param name="pushData">如果消息的接收者已经下线了,这个字段的内容就会被离线推送到接收者 /// <remarks>例如,一张图片消息的离线消息内容可以类似于:[您收到一条图片消息,点击查看] 这样的推送内容,参照微信的做法</remarks> /// <returns></returns> public Task <IAVIMMessage> SendMessageAsync( AVIMConversation conversation, IAVIMMessage message, bool receipt = true, bool transient = false, int priority = 1, bool will = false, IDictionary <string, object> pushData = null) { return(this.SendMessageAsync(conversation, message, new AVIMSendOptions() { Receipt = receipt, Transient = transient, Priority = priority, Will = will, PushData = pushData, })); }
/// <summary> /// 查询会话 /// </summary> /// <returns>The conversation async.</returns> /// <param name="clientId">Client identifier.</param> /// <param name="convId">Conv identifier.</param> internal Task <AVIMConversation> QueryConversationAsync(string clientId, string convId) { var tcs = new TaskCompletionSource <AVIMConversation>(); var where = new Dictionary <string, string> { { "objectId", convId } }; var queryConv = new ConvCommand { Where = new JsonObjectMessage { Data = JsonConvert.SerializeObject(where), }, }; var cmd = commandFactory.NewRequest(clientId, CommandType.Conv, OpType.Query); cmd.convMessage = queryConv; SendRequest(cmd).ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception.InnerException); } else { var res = t.Result; var queriedRes = res.convMessage; // TODO 实例化 AVIMConversation 对象 var convs = JsonConvert.DeserializeObject <List <Dictionary <string, object> > >(queriedRes.Results.Data); var rawData = convs[0]; var conv = new AVIMConversation { convId = convId, rawData = rawData }; // 将会话对象添加至对应的用户内存中 AVRealtime.Context.Post(() => { if (idToClient.TryGetValue(clientId, out var client)) { conv.Client = client; client.UpdateConversation(conv); } tcs.SetResult(conv); }); } }); return(tcs.Task); }
/// <summary> /// 向目标对话发送消息 /// </summary> /// <param name="conversation">目标对话</param> /// <param name="message">消息体</param> /// <param name="options">消息的发送选项,包含了一些特殊的标记<see cref="AVIMSendOptions"/></param> /// <returns></returns> public Task <IAVIMMessage> SendMessageAsync( AVIMConversation conversation, IAVIMMessage message, AVIMSendOptions options = default(AVIMSendOptions)) { var messageBody = message.Serialize(); message.ConversationId = conversation.ConversationId; message.FromClientId = this.ClientId; var cmd = new MessageCommand() .Message(messageBody) .ConvId(conversation.ConversationId) .Receipt(options.Receipt) .Transient(options.Transient) .Priority(options.Priority) .Will(options.Will); if (options.PushData != null) { cmd.PushData(options.PushData); } var directCmd = cmd.PeerId(this.ClientId); return(AVRealtime.AVIMCommandRunner.RunCommandAsync(directCmd).ContinueWith <IAVIMMessage>(t => { if (t.IsFaulted) { throw t.Exception; } else { var response = t.Result.Item2; message.Id = response["uid"].ToString(); message.ServerTimestamp = long.Parse(response["t"].ToString()); return message; } })); }
internal Task <AVIMMessage> SendMessageAsync(AVIMClient client, AVIMConversation conversation, AVIMMessage message) { var tcs = new TaskCompletionSource <AVIMMessage>(); var sendMsg = new DirectCommand { // TODO 完善消息体 Cid = conversation.convId, Msg = message.ToString() }; var cmd = commandFactory.NewRequest(client.ClientId, CommandType.Direct); cmd.directMessage = sendMsg; SendRequest(cmd).ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception.InnerException); } else { tcs.SetResult(message); } }); return(tcs.Task); }
internal Task OperateMembersAsync(AVIMConversation conversation, string action, string member = null, IEnumerable <string> members = null) { if (string.IsNullOrEmpty(conversation.ConversationId)) { throw new Exception("conversation id 不可以为空。"); } var membersAsList = Concat <string>(member, members, "加人或者踢人的时候,被操作的 member(s) 不可以为空。"); var cmd = new ConversationCommand().ConversationId(conversation.ConversationId) .Members(membersAsList) .Option(action) .PeerId(clientId); return(this.LinkedRealtime.AttachSignature(cmd, LinkedRealtime.SignatureFactory.CreateConversationSignature(conversation.ConversationId, ClientId, members, ConversationSignatureAction.Add)).OnSuccess(_ => { return AVRealtime.AVIMCommandRunner.RunCommandAsync(cmd).OnSuccess(t => { var result = t.Result; conversation.MemberIds = conversation.MemberIds.Concat(membersAsList); return result; }); }).Unwrap()); }
/// <summary> /// /// </summary> /// <param name="conversation"></param> /// <param name="message"></param> /// <param name="readAt"></param> /// <returns></returns> public Task ReadAsync(AVIMConversation conversation, IAVIMMessage message = null, DateTime?readAt = null) { var convRead = new ReadCommand.ConvRead() { ConvId = conversation.ConversationId, }; if (message != null) { convRead.MessageId = message.Id; convRead.Timestamp = message.ServerTimestamp; } if (readAt != null && readAt.Value != DateTime.MinValue) { convRead.Timestamp = readAt.Value.ToUnixTimeStamp(); } var readCmd = new ReadCommand().Conv(convRead).PeerId(this.ClientId); this.RunCommandAsync(readCmd); return(Task.FromResult(true)); }
public Task MarkAsReadAsync(string conversationId = null, string messageId = null, AVIMConversation conversation = null, AVIMMessage message = null) { var msgId = messageId != null ? messageId : message.Id; var convId = conversationId != null ? conversationId : conversation.ConversationId; if (convId == null && msgId == null) { throw new ArgumentNullException("发送已读回执的时候,必须指定 conversation id 或者 message id"); } lock (mutex) { var ackCommand = new AckCommand() .ReadAck().MessageId(msgId) .ConversationId(convId) .PeerId(this.ClientId); return(this.LinkedRealtime.AVIMCommandRunner.RunCommandAsync(ackCommand)); } }
/// <summary> /// 查询目标对话的历史消息 /// <remarks>不支持聊天室(暂态对话)</remarks> /// </summary> /// <param name="conversation">目标对话</param> /// <param name="beforeMessageId">从 beforeMessageId 开始向前查询(和 beforeTimeStampPoint 共同使用,为防止某毫秒时刻有重复消息)</param> /// <param name="afterMessageId"> 截止到某个 afterMessageId (不包含)</param> /// <param name="beforeTimeStampPoint">从 beforeTimeStampPoint 开始向前查询</param> /// <param name="afterTimeStampPoint">拉取截止到 afterTimeStampPoint 时间戳(不包含)</param> /// <param name="direction">查询方向,默认是 1,如果是 1 表示从新消息往旧消息方向, 0 则相反,其他值无效</param> /// <param name="limit">拉取消息条数,默认值 20 条,可设置为 1 - 1000 之间的任意整数</param> /// <returns></returns> public Task <IEnumerable <T> > QueryMessageAsync <T>(AVIMConversation conversation, string beforeMessageId = null, string afterMessageId = null, DateTime?beforeTimeStampPoint = null, DateTime?afterTimeStampPoint = null, int direction = 1, int limit = 20) where T : IAVIMMessage { var maxLimit = 1000; var actualLimit = limit > maxLimit ? maxLimit : limit; var logsCmd = new AVIMCommand() .Command("logs") .Argument("cid", conversation.ConversationId) .Argument("l", actualLimit); if (beforeMessageId != null) { logsCmd = logsCmd.Argument("mid", beforeMessageId); } if (afterMessageId != null) { logsCmd = logsCmd.Argument("tmid", afterMessageId); } if (beforeTimeStampPoint != null && beforeTimeStampPoint.Value != DateTime.MinValue) { logsCmd = logsCmd.Argument("t", beforeTimeStampPoint.Value.ToUnixTimeStamp()); } if (afterTimeStampPoint != null && afterTimeStampPoint.Value != DateTime.MinValue) { logsCmd = logsCmd.Argument("tt", afterTimeStampPoint.Value.ToUnixTimeStamp()); } if (direction == 0) { logsCmd = logsCmd.Argument("direction", "NEW"); } var subMessageType = typeof(T); var subTypeInteger = subMessageType == typeof(AVIMTypedMessage) ? 0 : FreeStyleMessageClassInfo.GetTypedInteger(subMessageType.GetTypeInfo()); if (subTypeInteger != 0) { logsCmd = logsCmd.Argument("lctype", subTypeInteger); } return(this.RunCommandAsync(logsCmd).OnSuccess(t => { var rtn = new List <IAVIMMessage>(); var result = t.Result.Item2; var logs = result["logs"] as List <object>; if (logs != null) { foreach (var log in logs) { var logMap = log as IDictionary <string, object>; if (logMap != null) { var msgStr = logMap["data"].ToString(); var messageObj = AVRealtime.FreeStyleMessageClassingController.Instantiate(msgStr, logMap); messageObj.ConversationId = conversation.ConversationId; rtn.Add(messageObj); } } } conversation.OnMessageLoad(rtn); return rtn.AsEnumerable().OfType <T>(); })); }
//public Task MarkAsReadAsync(string conversationId = null, string messageId = null, AVIMConversation conversation = null, AVIMMessage message = null) //{ // var msgId = messageId != null ? messageId : message.Id; // var convId = conversationId != null ? conversationId : conversation.ConversationId; // if (convId == null && msgId == null) throw new ArgumentNullException("发送已读回执的时候,必须指定 conversation id 或者 message id"); // lock (mutex) // { // var ackCommand = new AckCommand() // .ReadAck().MessageId(msgId) // .ConversationId(convId) // .PeerId(this.ClientId); // return this.RunCommandAsync(ackCommand); // } //} #region 查询对话中对方的接收状态,也就是已读回执 private Task <Tuple <long, long> > FetchAllReceiptTimestampsAsync(string targetClientId = null, string conversationId = null, AVIMConversation conversation = null, bool queryAllMembers = false) { var convId = conversationId != null ? conversationId : conversation.ConversationId; if (convId == null) { throw new ArgumentNullException("conversationId 和 conversation 不可以同时为 null"); } var cmd = new ConversationCommand().ConversationId(convId) .TargetClientId(targetClientId) .QueryAllMembers(queryAllMembers) .Option("max-read") .PeerId(clientId); return(this.RunCommandAsync(cmd).OnSuccess(t => { var result = t.Result; long maxReadTimestamp = -1; long maxAckTimestamp = -1; if (result.Item2.ContainsKey("maxReadTimestamp")) { long.TryParse(result.Item2["maxReadTimestamp"].ToString(), out maxReadTimestamp); } if (result.Item2.ContainsKey("maxAckTimestamp")) { long.TryParse(result.Item2["maxAckTimestamp"].ToString(), out maxAckTimestamp); } return new Tuple <long, long>(maxAckTimestamp, maxReadTimestamp); })); }
/// <summary> /// Leaves the conversation async. /// </summary> /// <returns>The async.</returns> /// <param name="conversation">Conversation.</param> public Task LeaveAsync(AVIMConversation conversation) { return(this.OperateMembersAsync(conversation, "remove", this.ClientId)); }
/// <summary> /// 从目标对话中剔除成员 /// </summary> /// <param name="conversation">目标对话</param> /// <param name="member">被剔除的单个成员</param> /// <param name="members">被剔除的成员列表</param> /// <returns></returns> public Task KickAsync(AVIMConversation conversation, string member = null, IEnumerable <string> members = null) { return(this.OperateMembersAsync(conversation, "remove", member, members)); }
/// <summary> /// 当前用户加入到目标的对话中 /// </summary> /// <param name="conversation">目标对话</param> /// <returns></returns> public Task JoinAsync(AVIMConversation conversation) { return(this.OperateMembersAsync(conversation, "add", this.ClientId)); }
/// <summary> /// 直接将其他人加入到目标对话 /// <remarks>被操作的人会在客户端会触发 OnInvited 事件,而已经存在于对话的用户会触发 OnMembersJoined 事件</remarks> /// </summary> /// <param name="conversation">目标对话</param> /// <param name="member">单个的 Client Id</param> /// <param name="members">Client Id 集合</param> /// <returns></returns> public Task InviteAsync(AVIMConversation conversation, string member = null, IEnumerable <string> members = null) { return(this.OperateMembersAsync(conversation, "add", member, members)); }
internal void HandleReceiveMessage(AVIMConversation conversation, AVIMMessage message) { message.Conversation = conversation; OnReceivedMessage?.Invoke(message); }
internal void UpdateConversation(AVIMConversation conv) { conv.Client = this; idToConversation.Remove(conv.convId); idToConversation.Add(conv.convId, conv); }
/// <summary> /// Get conversation. /// </summary> /// <returns>The conversation.</returns> /// <param name="client">Client.</param> /// <param name="conversationId">Conversation identifier.</param> public static AVIMConversation GetConversation(this AVIMClient client, string conversationId) { return(AVIMConversation.CreateWithoutData(conversationId, client)); }
internal void HandleJoinedConversation(AVIMConversation conversation) { OnJoinedConversation?.Invoke(conversation); }
/// <summary> /// mark the conversation as read with conversation id. /// </summary> /// <param name="conversationId">conversation id</param> /// <returns></returns> public Task ReadAsync(string conversationId) { var conv = AVIMConversation.CreateWithoutData(conversationId, this); return(this.ReadAsync(conv)); }
public void OnNoticeReceived(AVIMNotice notice) { var cid = notice.RawData["cid"].ToString(); var conversation = new AVIMConversation(cid); var args = new AVIMOnMembersChangedEventArgs() { }; var generators = new Func <AVIMNotice, AVIMOnMembersChangedEventArgs>[] { (e) => { return(new AVIMOnMembersChangedEventArgs() { Conversation = conversation, AffectedType = AVIMConversationEventType.Joined, Oprator = e.RawData["initBy"].ToString(), OpratedTime = DateTime.Now }); }, (e) => { return(new AVIMOnMembersChangedEventArgs() { Conversation = conversation, AffectedType = AVIMConversationEventType.Left, Oprator = e.RawData["initBy"].ToString(), OpratedTime = DateTime.Now }); }, (e) => { return(new AVIMOnMembersChangedEventArgs() { Conversation = conversation, AffectedType = AVIMConversationEventType.MembersJoined, Oprator = e.RawData["initBy"].ToString(), AffectedMembers = new List <string>(e.RawData["m"] as string[]) }); }, (e) => { return(new AVIMOnMembersChangedEventArgs() { Conversation = conversation, AffectedType = AVIMConversationEventType.MembersLeft, Oprator = e.RawData["initBy"].ToString(), AffectedMembers = new List <string>(e.RawData["m"] as string[]), OpratedTime = DateTime.Now }); }, (e) => { var rtn = new AVIMOnMembersChangedEventArgs() { Conversation = conversation, AffectedType = AVIMConversationEventType.Invited, AffectedMembers = new List <string>(e.RawData["m"] as string[]), OpratedTime = DateTime.Now }; return(rtn); }, (e) => { var rtn = new AVIMOnMembersChangedEventArgs() { Conversation = conversation, AffectedType = AVIMConversationEventType.Kicked, AffectedMembers = new List <string>(e.RawData["m"] as string[]), OpratedTime = DateTime.Now }; return(rtn); } }; var op = notice.RawData["op"].ToString(); int ssIndex = Array.IndexOf(listeningCommandNames, op); var action = generators[ssIndex]; args = action(notice); if (m_OnConversationMembersChanged != null) { m_OnConversationMembersChanged(this, args); } }
internal void HandleMembersJoined(AVIMConversation conversation, List <string> memberIds) { OnMembersJoined?.Invoke(conversation, memberIds); }
internal void HandleMemebersLeft(AVIMConversation conversation, List <string> memberIds) { OnMembersLeft?.Invoke(conversation, memberIds); }
/// <summary> /// mark the conversation as read /// </summary> /// <param name="conversation">conversation</param> /// <returns></returns> public Task ReadAsync(AVIMConversation conversation) { var readCmd = new ReadCommand().ConvId(conversation.ConversationId).PeerId(this.ClientId); return(this.LinkedRealtime.RunCommandAsync(readCmd)); }