Deleting Messages a bot has sent Discord.net - c#

I am attempting to create a bot that has the ability to delete only the bots messages after a command has been done.
I am aware of how i know that the command has taken place however I am having issues with only deleting the messages that the bot has sent.
await Message.ModifyAsync(msg => msg.Content = "test [edited]");
However this only occurs to the last message that has been sent (This can be fixed relatively easily and I know how to do this) and importantly would otherwise occur to all the messages in the chat! What i want to do is make it so that I only delete messages that were sent by the bot in the first place.
Thanks

Get and store the message that the bot sent as a variable, and delete it later.
var botMsg = await ReplyAsync("A message!");
await botMsg.DeleteAsync();
If you need to delete multiple messages, create a list and store each message to the list. Then use await Context.Channel.DeleteMessagesAsync(list) at the end of the command.
EDIT
There are overload methods for passing both list of message ID and the message itself.
Example of passing a list of message ID:
List<ulong> msgToDel = new List<ulong>();
msgToDel.Add((await ReplyAsync("test1")).Id); //Send a msg, then add the msg ID to the list.
msgToDel.Add((await ReplyAsync("test2")).Id);
//Blah...
await Context.Channel.DeleteMessagesAsync(msgToDel);
You can check the documentation for the DeleteMessagesAsync() here.

Related

Bot Framework Read UserState data outside of dialog or resume to conversation dialog

I have a PizzaBot. After getting the order I save the data to the UserState. After that the user gets a button(ActionTypes.OpenUrl) to pay the order on a different system. Everything works fine till now.
However, when the payment service call my api, I cannot get the UserState data anymore. I have tried to send a Proactive notification, the "You have paid successfully" message is being shown, but I cannot retrieve UserData.
I get my conversation id conversationReference, but I have no idea what I should call in the BotCallback to resume to the conversation.
foreach (var conversationReference in _conversationReferences.Values)
{
await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, BotCallback, default);
}
Do you have any example of that for me?
I have fixed this issue thanks to George.
On the UserState documentation page this is written:
User state is available in any turn that the bot is conversing with
that user on that channel, regardless of the conversation.
This means if my NotificationController is called the UserState is there somewhere.
So, I have created a proactive MainDialog on the BotCallback with an option: see: Starting A Dialog From From A Proactive Message and read UserState data if the option is filled and coming from my NotificationController

Reliable/idempotent mailing from Azure Function app

I'm currently evaluating Azure Functions and I'm trying to find a way/pattern to reliable and idempotent send Emails (and store them in a db). I already read a lot about Sagas, 2PC, Eventual Consistency, but I don't know how to apply these concepts to my situation.
I already have a few business objects stored in a database. Now I would like to add an endpoint which e.g. sends a project summary based on a template. Therefore I created a http triggered function and a CreateEmail method. This is the pseudo code of it
public static async void CreateEmail(QueueClient queue, Guid id)
{
// add the message to the queue, but keep it hidden for 3 min
var sendReceipt = await queue.SendMessageAsync(id.ToString(), TimeSpan.FromSeconds(180))
.ConfigureAwait(false);
//message.PopReceipt is now populated, and only this client can operate on the message until visibility timeout expires
try
{
//Create the mail entity in the db and commit
CreateEmailEntityAndCommit(id);
}
catch (Exception)
{
// Delete the SendMail queue message, because an error occured in db operations
queue.DeleteMessage(sendReceipt.Value.MessageId, sendReceipt.Value.PopReceipt);
throw;
}
// Everything is fine. Mark the message as visible to the email send function
queue.UpdateMessage(sendReceipt.Value.MessageId, sendReceipt.Value.PopReceipt,
visibilityTimeout: TimeSpan.Zero);
}
The code actually does not send the mail, but only creates a database entity and queues a message to the Azure Queue Storage. Another, queue triggered function picks up the messages, sends the mail and updates the status in the db:
public void Run([QueueTrigger("myqueue-items")]string id, ILogger log)
{
if (CheckEmailStatus() == Status.Sent)
{
// Message received twice
return;
}
SendEmail();
UpdateEmailStatus(Status.Sent); // How do we deal with exceptions here? email sent successfully, but status not updated...
}
And here is my problem: If anything goes wrong immediately after sending the mail, the status is not updated. When azure delivers the message again, the Mail would be send again. I guess there is a pattern to avoid such a situation.
Since you are using storage queue, you need to handle idempotency or deduplication at the receiver function end using some identifier of the entity. For example, you can maintain a cache of ids which you can look up to check if currently received id exists, the cache can be set with a reasonable TTL of your desired time window.
Note: Duplicate detection is out of the box in Service Bus queue.
Also you might want to look at Durable Functions.

Discord.Net - Add reaction to previous message from command

From a command, I want to be able to grab the previous message from the chat and add reactions to that message. I am using this line of code to get the previous message but it returns a IEnumerable<IMessage>.
var messages = await Context.Channel
.GetMessagesAsync(Context.Message, Direction.Before, 1)
.FlattenAsync();
IMessages do not have an add reaction function. I tried going through multiple ways to get the socket user message from the last message but can not find any way to get a socket user message from an IMessage.
Simply cast to an IUserMessage.
If cache isn't enabled you won't be able to get a socket message, you'd get a rest message instead. That said, a socket message isn't required, so the interface should suffice.

Is there a way to "flush" the messages into Facebook Messenger?

TL;DR: the bot takes 2-9 seconds to send any message to the user, even if I send the message from the very first line in MessagesController.cs.
I have used the Bot Framework to create a couple of bots for Facebook Messenger and I noticed that one of them is significantly slower than the other.
Both bots have the code below as the very first lines in the MessagesController.cs. This is supposed to send the Typing indicator to the user.
One bot consistently takes 2 seconds to show this typing indicator to the user on Facebook, while the other takes 9 seconds.
Activity typing = activity.CreateReply(null);
typing.ServiceUrl = activity.ServiceUrl;
typing.Type = ActivityTypes.Typing;
ConnectorClient connector = new ConnectorClient(new Uri(typing.ServiceUrl));
await connector.Conversations.SendToConversationAsync(typing);
The second bot indeed does much more work (calling various web APIs), but since these lines are the very first in the controller, I expect the typing indicator to be sent to the user immediately, after which the bot can continue doing its work.
However, it seems that the messages (including the typing indicator) are not sent until the bot completes its work.
Is there a way to "flush" the messages to the user to have a typing indicator sent immediately, or am I encountering some other issue?
Update: I've tried the ConnectorClient.Dispose() method but it doesn't seem to help make it any faster to send messages.
I am not sure what you mean by "flushing" the messages to the user but your bot should show the typing indicator immediately until you type a message and there is some process in the background. To avoid processing information until the user types a message you can use the ActivityTypes like this:
if (activity.Type == ActivityTypes.Message)
{
Activity typing = activity.CreateReply(null);
typing.ServiceUrl = activity.ServiceUrl;
typing.Type = ActivityTypes.Typing;
ConnectorClient connector = new ConnectorClient(new Uri(typing.ServiceUrl));
await connector.Conversations.SendToConversationAsync(typing);
}
else
{
HandleSystemMessage(activity);
}
...
However, it makes sense that the user cannot type anything until the application has already given a answer back to the previous question.

Edit MSMQ messages in a queue

I need to be able to edit messages in my error queue (so that they can be resent to the actual queue for reprocessing).
I would like to make my own custom tool to do this (because my messages require specific formatting to make them easily readable by support personnel).
I know that this is possible because the application "QueueExplorer" does this.
Does anyone know how I can load an MSMQ message (that is not the first one in the queue), edit it, and save it back to the queue?
Iterate through the messages, using something like this:
List<Message> msgList = new List<Message>();
using (MessageEnumerator me = queue.GetMessageEnumerator2())
{
while (me.MoveNext(new TimeSpan(0, 0, 0)))
{
Message message = me.Current;
msgList.Add(message)
}
}
You can then iterate through the list, processing each message.
Create a new message, based on the original. Then remove the existing message, and add the new one.
foreach (Message message in msgList)
{
//Create a new message as required, add it, then remove the old message
MessageQueue.ReceiveById(message.MessageId);
}
MSMQ messages are supposed to be immutable. The best you can do is read the message and send an edited copy of the message back to the queue.

Categories

Resources