Discord.NET C# MessageReceived getting called too many times - c#

i tried this code which i've copied from the github page of discord.net this one works perfectly fine:
using Discord;
using Discord.WebSocket;
using System;
using System.Threading.Tasks;
namespace Adivisor
{
public class Program
{
private DiscordSocketClient _client;
public static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult();
public async Task MainAsync()
{
_client = new DiscordSocketClient();
_client.Log += Log;
_client.MessageReceived += MessageReceived;
string token = ":P";
await _client.LoginAsync(TokenType.Bot, token);
await _client.StartAsync();
await Task.Delay(-1);
}
private async Task MessageReceived(SocketMessage message)
{
if (message.Content == "!hi")
{
await message.Channel.SendMessageAsync("Hello!");
}
}
private Task Log(LogMessage msg)
{
Console.WriteLine(msg.ToString());
return Task.CompletedTask;
}
}
}
after i made a little editing on MessageReceived now it looks like this:
private async Task MessageReceived(SocketMessage message)
{
await message.Channel.SendMessageAsync("Hello!");
}
pratically i just removed the if, but there is a huge differnce, seems like the without the if MessageReceived gets called forever...

Like what Xiaoy312 stated, whenever your bot send a message, it also receives it's own message.
(The same also applies for your own user account! Try doing an #everyone ping in chat and you will see it being highlighted even though it was you who sent it.)
You can make your bot ignore it other bots messages by doing this:
//Ignores all bots messages
//Where message is your received SocketMessage
if (message.Author.IsBot) { return; }
Or you can make it check if the message's author's ID equals to the bot's ID. You can check the documentation here.

Related

Discord.NET run multiple bots from one console app project

I've seen many examples how to run Discord.NET Bot but all those examples show how to run 1 bot per
1 console app project or one bot sharded with servers so is this library designed only for 1<-->1 approach because I saw also singleton is used for connecting part? Is it possible to run multiple bots from one codebase? I need this to keep track bots/connectons and see statuses in webapplication but it might be bad decision if I go with multiple console applications approach.
You should probably use object and class for each discord bot though but I wanted to give you idea of how can you achieve such an effect. I would probably also use better logging system (maybe some logging library?). But if I were you I would think maybe about using docker and docker-compose?
Cheers
using System.Threading;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
namespace temp
{
public class Program
{
public static async Task Bot1(Func<LogMessage, Task> log, CancellationToken cancellationToken)
{
var client = new DiscordSocketClient();
client.Log += log;
await client.LoginAsync(TokenType.Bot, "token1");
await client.StartAsync();
await Task.Delay(-1, cancellationToken);
}
public static async Task Bot2(Func<LogMessage, Task> log, CancellationToken cancellationToken)
{
var client = new DiscordSocketClient();
client.Log += log;
await client.LoginAsync(TokenType.Bot, "token2");
await client.StartAsync();
await Task.Delay(-1, cancellationToken);
}
public static void Main()
{
var cancellationToken = new CancellationTokenSource();
Console.CancelKeyPress += (sender, args) =>
{
cancellationToken.Cancel();
args.Cancel = true;
};
Task.WhenAll(new Task[]
{
Bot1(Log, cancellationToken.Token),
Bot2(Log, cancellationToken.Token)
});
}
private static async Task Log(LogMessage message)
{
Console.WriteLine(message);
}
}
}

How Can I Keep My Discord Bot Logged In Without Resorting To Task.Delay?

I'm currently running a Discord bot, but it won't stay logged in unless I add await Task.Delay(-1) to the method I use to log-in. I'm suspecting this is causing me some issues in later parts of my code.
Here is how I connect:
public override async Task ConnectToClientAsync()
{
await this._client.LoginAsync(TokenType.Bot, this.Token);
await this._client.StartAsync();
await Task.Delay(-1);
}
How do I keep my bot online without resorting to using Task.Delay(-1)? It just logs in, and once completed successfully it then terminates the program (as it doesn't stay logged in without this delay).
Main
class Program
{
static async Task Main(string[] args)
{
var newBot = new WelcomeBot(674094599903641628);
await newBot.LaunchBot();
}
}
WelcomeBot
public class WelcomeBot : BasicBot, IMessageWriter, IMessageReader
{
private ulong _channelId;
public WelcomeBot(ulong channelId) : base()
{
this._client = new DiscordSocketClient();
this._channelId = channelId;
ConfigureBotFunctionality();
}
private void ConfigureBotFunctionality()
{
Interact_UserEntryAndExit();
}
private void Interact_UserEntryAndExit()
{
this._client.UserJoined += AnnounceUserJoiningAsync;
this._client.UserLeft += AnnounceUserLeavingAsync;
this._client.Connected += OnConnectAnnouncementAsync;
}
public async Task LaunchBot()
{
await ConnectToClientAsync();
}
public override async Task ConnectToClientAsync()
{
await this._client.LoginAsync(TokenType.Bot, this.Token);
await this._client.StartAsync();
await Task.Delay(-1);
}
private async Task OnConnectAnnouncementAsync()
{
// ..
}
private async Task AnnounceUserLeavingAsync(SocketGuildUser leavingUser)
{
//..
}
private async Task AnnounceUserJoiningAsync(SocketGuildUser joinedUser)
{
//..
}
// Other functions.
}
Just add a small delay, 300 or 400 or something.

Stuck in IMobileServiceTable.ToListAsync()

I have modified the Xamarin/Azure TODO example. But the code is stuck in
IMobileServiceTable.ToListAsync()
This is my IO class:
class DataIO
{
BackgroundWorker DatabaseWorker = new BackgroundWorker();
IMobileServiceTable<UserPosition> PositionTable;
MobileServiceClient client;
public DataIO()
{
Init();
}
public void Init()
{
client = new MobileServiceClient(Constants.ApplicationURL);
PositionTable = client.GetTable<UserPosition>();
}
async void AddEntry(UserPosition entry)
{
await PositionTable.InsertAsync(entry);
}
public async Task<List<UserPosition>> GetEntries()
{
List<UserPosition> Entries = await PositionTable.ToListAsync();
return Entries;
}
public async void DeleteEntry(UserPosition entry)
{
await PositionTable.DeleteAsync(entry);
}
public async void AddToDatabase(UserPosition item)
{
await PositionTable.InsertAsync(item);
}
}
The debugger dosen't neither step over it nor throws an error.
How to handle that?
In an earlier call, there wasn't any problem.
EDIT:
I've rewritten the GetEntries() method to:
public async Task<List<UserPosition>> GetEntries()
{
Task<List<UserPosition>> task = PositionTable.ToListAsync();
List<UserPosition> entries = await task;
return entries;
}
according to this example. But the debugger just stays in the line
Task<List<UserPosition>> task = PositionTable.ToListAsync();
AFAIK, IMobileServiceTable.ToListAsync() would send the request as follows for retrieving the result:
Get https://<your-app-name>.azurewebsites.net/tables/UserPosition
I would recommend you using Fiddler to collect the network traces when calling IMobileServiceTable.ToListAsync(). Also, you could access the table endpoint from your mobile app via the browser to make sure your mobile app could work as expected. Additionally, here is a great tutorial about Handling Data in Mobile Clients, you could refer to it.

Run time error and Program exits when using - Async and await using C#

I am trying to use the concept of async and await in my program. The program abruptly exits. I am trying to get the content length from few random urls and process it and display the size in bytes of each url.
Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
namespace TestProgram
{
public class asyncclass
{
public async void MainCall() {
await SumPageSizes();
}
public async Task SumPageSizes(){
List<string> urllist = GetUrlList();
foreach (var url in urllist)
{
byte[] content = await GetContent(url);
Displayurl(content, url);
}
}
private void Displayurl(byte[] content, string url)
{
var length = content.Length;
Console.WriteLine("The bytes length for the url response " + url + " is of :" +length );
}
private async Task<byte[]> GetContent(string url)
{
var content = new MemoryStream();
try
{
var obj = (HttpWebRequest)WebRequest.Create(url);
WebResponse response = obj.GetResponse();
using (Stream stream = response.GetResponseStream())
{
await stream.CopyToAsync(content);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
return content.ToArray();
}
private List<string> GetUrlList()
{
var urllist = new List<string>(){
"http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
"http://msdn.microsoft.com",
"http://msdn.microsoft.com/en-us/library/hh290136.aspx",
"http://msdn.microsoft.com/en-us/library/ee256749.aspx",
"http://msdn.microsoft.com/en-us/library/hh290138.aspx",
"http://msdn.microsoft.com/en-us/library/hh290140.aspx",
"http://msdn.microsoft.com/en-us/library/dd470362.aspx",
"http://msdn.microsoft.com/en-us/library/aa578028.aspx",
"http://msdn.microsoft.com/en-us/library/ms404677.aspx",
"http://msdn.microsoft.com/en-us/library/ff730837.aspx"
};
return urllist;
}
}
}
Main
public static void Main(string[] args)
{
asyncclass asyncdemo = new asyncclass();
asyncdemo.MainCall();
}
MainCall returns an uncompleted task and no other line of code is present beyond that, so your program ends
To wait for it use:
asyncdemo.MainCall().Wait();
You need to avoid async void and change MainCall to async Task in order to be able to wait for it from the caller.
Since this seems to be a console application, you can't use the await and async for the Main method using the current version of the compiler (I think the feature is being discussed for upcoming implementation in C# 7).
The problem is that you don't await an asynchron method and therefore you application exits before the method ended.
In c# 7 you could create an async entry point which lets you use the await keyword.
public static async Task Main(string[] args)
{
asyncclass asyncdemo = new asyncclass();
await asyncdemo.MainCall();
}
If you want to bubble your exceptions from MainCall you need to change the return type to Task.
public async Task MainCall()
{
await SumPageSizes();
}
If you wanted to run your code async before c# 7 you could do the following.
public static void Main(string[] args)
{
asyncclass asyncdemo = new asyncclass();
asyncdemo.MainCall().Wait();
// or the following line if `MainCall` doesn't return a `Task`
//Task.Run(() => MainCall()).Wait();
}
You have to be very careful when using async void methods. Those will not be awaited. One normal example of an async void is when you are calling an awaitable method inside a button click:
private async void Button_Click(object sender, RoutedEventArgs e)
{
// run task here
}
This way the UI won't be stuck waiting for the button click to complete.
On most custom methods you will almost always want to return a Task so that you are able to know when your method is finished.

C# .net WebSocket client never disconnects

Been using C# Websocket client in my app using System.Net.WebSockets. All my code to send and receive is working well, however I can not for the life of me successfully disconnect (Which i need to do so i can then use the client again w/ different hostname). I have created a quick demo to show my problem.
This is my Program code:
class Program
{
static void Main(string[] args)
{
GetDocList();
Console.ReadLine();
}
static async Task<string> GetDocList()
{
var client = new myWSClient(new Uri("ws://localhost:9999/qlcplusWS"));
var docs = await client.ConnectAndDisconnect();
return docs;
}
}
This is my Class that I am using
public class myWSClient
{
private ClientWebSocket _client;
public Uri _myURI;
public myWSClient(Uri MyURI)
{
_client = new ClientWebSocket();
_myURI = MyURI;
}
public async Task<string> ConnectAndDisconnect()
{
string dummyreturn = "";
await _client.ConnectAsync(_myURI, CancellationToken.None);
Console.WriteLine("Connected");
string status = "";
Console.WriteLine("Waiting to Disconnect, but it will never happen :(");
await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, status, CancellationToken.None);
Console.WriteLine("Disconnected mate");
return dummyreturn;
}
}
Am I using the wrong method or is my code just syntactically wrong?
You have to wait for the methods to return as those are asynchronous and the main function is going to continue executing after starting the task of the GetDocList() method.
GetDocList().Wait();

Categories