I am currently making a bot for my server and I'm trying to make a function to when the bot receives .raid it spams messages I've tried loops but it keeps messing up my code. This is what I have for my C#. I just cant seem to get a loop working specifically in discord.
//RAID
private void RegisterRaidCommand()
{
commands.CreateCommand("raid")
.Do(async (e) =>
{
await e.Channel.SendMessage("READY SIR!");
//here is where the loop needs to start
//here is where the spam message goes
});
}
i made a spam/raid command using a normal for loop and it works fine for me. This command just takes in 2 parameters, one for the word or phrase that will be spammed and the int parameter for the amount of times you want it to be spammed.
[Command("spam")]
[RequireUserPermission(GuildPermission.Administrator)]
public async Task CMD14(int times, [Remainder] string Word)
{
for (int i = 0; i < times; i++)
{
await Context.Channel.SendMessageAsync($"`{Word}`");
}
}
Hope this helps in some way, shape or form :)
Related
This question has been answered multiple times, but I'm still not getting it.
I am using an example from this page: https://www.codeproject.com/Articles/1124691/SignalR-Progress-Bar-Simple-Example-Sending-Live-D
However, I've modified the SendProgress method a bit, to send the message only to the specific connection, not all clients:
public static void SendProgress(string connectionId, string progressMessage, int progressCount, int totalItems)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<RealTimeProgressBar.ProgressHub>();
var percentage = (progressCount * 100) / totalItems;
hubContext.Clients.Client(connectionId).AddProgress(progressMessage, percentage + "%");
}
I am getting connection Id from overrided OnConnected method:
public override Task OnConnected()
{
Environments.ConnectionId = Context.ConnectionId;
return base.OnConnected();
}
I'm currently storing it in a static class Environments, I guess there is a better way for doing so, but I don't know it yet :)
The question is, when I open for example two instances of my web page in browser, the progress bar is still being shown for all of these instances, though the connectionIds on these pages are different (checked it in SendProgress function).
What is wrong here?
Perhaps, I should change something in js code?
$(function () {
// Reference the auto-generated proxy for the hub.
var progress = $.connection.progressHub;
console.log(progress);
// Create a function that the hub can call back to display messages.
progress.client.AddProgress = function (message, percentage) {
ProgressBarModal("show", message + " " + percentage);
$('#ProgressMessage').width(percentage);
if (percentage == "100%") {
ProgressBarModal();
}
};
$.connection.hub.start().done(function () {
var connectionId = $.connection.hub.id;
console.log(connectionId);
});
});
As i'm not really sure if js funcs really uses Environments.ConnectionId or smthing else..
Thanks!
Edit: What I want to achive is to send unique progress bars for every opened page. e.g. when I press the button on a first page, I'm starting to collect data and progress bar reflects that. I also open another page in a browser, and collect data from another source, so the progress bar should reflect that for this page as well.
my controller method:
public ActionResult Generate(InputDataViewModel viewModel, string connectionId)
{
...
var Tasks = getResultsWithProgressBar(viewModel.jobId, connectionId);
...
return RedirectToAction("Details", new { id = job.JobDataId });
}
and somewhere inside this "getResult" is a function that actually calls progress bar(SendProgress)
Your change should work fine.
You are using a static ConnectionId, so only your last browser, the browser you opened last(or connected last) will see the progress bar as well as updates.
This is the only one i made apart apart from adding in the static Environment.ConnectionId.
//PUSHING DATA TO ALL CLIENTS
// hubContext.Clients.All.AddProgress(progressMessage, percentage + "%");
hubContext.Clients.Client(Environments.ConnectionId).AddProgress(progressMessage, percentage + "%");
So if you open 10 browser windows and click on the button on all those, one by one, only the browser you initially opened last will see the the progress bar as well as updates, but it will see updates from all the 10 browsers shown on that single progress bar!
It is fun to see though!
When I tried your code, I saw the behavior you observed initially. But when I opened two separate Incognito browsers, I see the correct behavior. Close the IIS express site, rebuild and retry it.
Edit:
If you need each tab to have its own progress bar, then you will need one of the two approaches below:
A way to identify which rest request came from which connectionId. If you want to continue using the current code. Just pass in the connection Id to the LongRunningProcess. Client code below:
var progress = $.connection.progressHub;
var connectionId = $.connection.hub.id;
$.getJSON("/Home/LongRunningProcess",
{"connectionId":connectionId},
function (data) {
if (!data) {
alert("Success");
}
else
{
alert(data);
}
});
Server code would be:
public JsonResult LongRunningProcess(string connectionId)
{
//THIS COULD BE SOME LIST OF DATA
int itemsCount = 100;
for (int i = 0; i <= itemsCount; i++)
{
//SIMULATING SOME TASK
Thread.Sleep(500);
//CALLING A FUNCTION THAT CALCULATES PERCENTAGE AND SENDS THE DATA TO THE CLIENT
Functions.SendProgress(connectionId, "Process in progress...", i , itemsCount);
}
return Json("", JsonRequestBehavior.AllowGet);
}
The other option is to call a signalr method on the server instead of a rest method. Create a new hub method in the ProgressHub like below:
public void LongRunningHubMethod()
{
//THIS COULD BE SOME LIST OF DATA
int itemsCount = 100;
for (int i = 0; i <= itemsCount; i++)
{
//SIMULATING SOME TASK
Thread.Sleep(500);
//CALLING A FUNCTION THAT CALCULATES PERCENTAGE AND SENDS THE DATA TO THE CLIENT
Functions.SendProgress(Context.ConnectionId, "Process in progress...", i, itemsCount);
}
}
The client would then just call in the hub method on click like below:
var progress = $.connection.progressHub;
var connectionId = $.connection.hub.id;
progress.invoke('LongRunningHubMethod');
I just started in coding c#, and I am making a Bot for my discord server. I recently added a command !meme, where it would randomly pull from around 100 different pictures to send in the chat. The second I implemented this command, everyone just totally abused it, and it was at the point where there was like 15 pictures popping up in chat every 2 seconds because of the !meme spam.
I want to be able to add a 3 second delay before the command itself can be used again. I tried using Thread.Sleep(3000); and that did not work. Same for
await Task.Delay(3000); which I used inside of the async.
private void RegisterMemeCommand()
{
commands.CreateCommand("Meme")
.Do(async (e) =>
{
int RandomMeme = rng.Next(MemeList.Length);
string memetopost = MemeList[RandomMeme];
await e.Channel.SendFile(memetopost);
});
}
As I don't have complete code, from what you have up in the question, try this:
var lastSentOn=DateTime.MinValue;
commands.CreateCommand("Meme")
.Do(async (e) =>
{
if((DateTime.Now - lastSentOn).TotalSeconds > 3)
{
int RandomMeme = rng.Next(MemeList.Length);
string memetopost = MemeList[RandomMeme];
lastSentOn = DateTime.Now;
await e.Channel.SendFile(memetopost);
}
});
You may need to associate lastSentOn with some user id etc. A dictionary will be helpful in this scenario.
I have a function that is run once every second by a timer. The purpose of the function is to request data through an API and then update a list and some textboxes with the results. For the most part it runs like clockwork, but every couple of hours I get an ArgumentOutOfRangeException.
For whatever reason, either that one API request fails or the list doesn't update fast enough. Either way the function tries to update texboxes and variables using an empty list, hence the ArgumentOutOfRangeException.
Now this data is mostly not being stored for any length of time, and the function would just run again in another second anyway if not for the error popping up and stalling everything. I hadn't used C# before I made this program so I'm not sure how best to utilize the "catch" statement to just make the program ignore it and keep going. Actually it would be good if the number of failures was logged in an integer variable so that the program could determine if something was actually wrong instead of just a momentary glitch. How would you write the catch statement for this?
try
{
GetQuoteResponse resp = GetQuoteResponse.GetQuote(questradeToken, quotesSymbolIds);
List<Level1DataItem> quotes = resp.Quotes;
QuoteStream_Data.Clear();
for (int i = 0; i < quotes.Count; ++i)
{
Level1DataItem quote = quotes[i];
QuoteStream_Data.Add(new QuoteStream_Entry { lastTradePrice = Convert.ToDecimal(quote.m_lastTradePrice)});
}
XIVPriceBox.Invoke(new Action(() => XIVPriceBox.Text = QuoteStream_Data[0].lastTradePrice.ToString()));
HVIPriceBox.Invoke(new Action(() => HVIPriceBox.Text = QuoteStream_Data[1].lastTradePrice.ToString()));
TVIXPriceBox.Invoke(new Action(() => TVIXPriceBox.Text = QuoteStream_Data[2].lastTradePrice.ToString()));
XIVCurrentPrice = QuoteStream_Data[0].lastTradePrice;
TVIXCurrentPrice = QuoteStream_Data[2].lastTradePrice;
}
catch
{
}
try
{
// ...
}
catch(ArgumentOutOfRangeException ex)
{
LogException(ex);
}
I've been experimenting with SignalR today and It's really neat. Basically what I wanted to achieve is the following:
As soon as a device connects it should send a message to the first one. If there are more devices than 1 connected I would like to send two messages. One to all except the last connected client. And one message to only the last connected client.
The code I've been using works perfect when I place it in a custom API controller and basically call the action, but that's not what I want.
I would like to send the messages as soon as a device connects within OnConnected without any user interaction, but when I place my code inside the OnConnected override it stops working. It doesn't send to the specific clients anymore (first connected and last connected).
I hope someone is able to help me out with this, because I've been banging my head for a few hours now.
public override System.Threading.Tasks.Task OnConnected()
{
UserHandler.ConnectedIds.Add(Context.ConnectionId, UserHandler.ConnectedIds.Count + 1);
int amountOfConnections = UserHandler.ConnectedIds.Count;
var lastConnection = UserHandler.ConnectedIds.OrderBy(x => x.Value).LastOrDefault();
var allExceptLast = UserHandler.ConnectedIds.Take(amountOfConnections - 1).Select(x => x.Key).ToList();
if (amountOfConnections == 1)
{
Clients.Client(UserHandler.ConnectedIds.First().Key).hello("Send to only(also first) one");
}
else
{
Clients.Clients(allExceptLast).hello("Send to everyone except last");
Clients.Client(lastConnection.Key).hello("Send to only the last one");
}
return base.OnConnected();
}
Unless I miss something from your question, the solution looks pretty simple to me, you just need to switch to using
Clients.Caller.hello("Send to only the last one");
instead of trying to understand yourself who's the last connected id. Same for the other ones, you can use:
Clients.Others.hello("Send to everyone except last");
You do not need all the logic you setup, those 2 lines do what you need, and they work inside OnConnected.
Thanks for all the help (upvoted you guys). Actually found the problem.. it was inside my client. I first subscribed to the 'hello' function and after that I started the HubConnection. As soon as I changed this order everything worked fine.
It worked with the following client code:
private async Task ConnectToSignalR()
{
var hubConnection = new HubConnection("url");
hubConnection.Headers["x-zumo-application"] = "clientapikey";
IHubProxy proxy = hubConnection.CreateHubProxy("ChatHub");
proxy.On<string>("hello", async (msg) =>
{
Console.WriteLine(msg);
});
await hubConnection.Start();
}
Since you haven't established a connection yet, trying to call your client .hello() function within OnConnected is not possible at this point. However, we can define a server hub method and immediately call that upon our connection .done callback. Then, in our new server method we can reallocate the logic you currently have in OnConnected.
This will change our setup quite a bit and introduce some additional steps, but observe the following example...
// WhateverHub
public override Task OnConnected()
{
return base.OnConnected()
}
public void AfterConnected()
{
// if(stuff) -- whatever if/else first user/last user logic
// {
Clients.Caller.hello("message")
// }
}
var proxy= $.connection.whateverHub;
proxy.client.hello = function(message) {
// last step in event chain
}
$.connection.hub.start().done(function () {
proxy.server.afterConnected() // call AfterConnected() on hub
});
So the basic idea here is to first
Connect => .done(function() { ... });
Call server.afterConnected()
Execute logic within that method
If we're satisfied with conditions call our .hello() client function
Note - this implementation is for a JavaScript client - but the same idea can be translated to a .net client. This is mostly an architectural issue.
well... you are returning a task... so i think that may be the issue...
you should first execute your code and then return the task... or put a ContinueWith... like...
public override Task OnConnected()
{
Task task = new Task(() =>
{
UserHandler.ConnectedIds.Add(Context.ConnectionId, UserHandler.ConnectedIds.Count + 1);
int amountOfConnections = UserHandler.ConnectedIds.Count;
var lastConnection = UserHandler.ConnectedIds.OrderBy(x => x.Value).LastOrDefault();
var allExceptLast = UserHandler.ConnectedIds.Take(amountOfConnections - 1).Select(x => x.Key).ToList();
if (amountOfConnections == 1)
{
Clients.Client(UserHandler.ConnectedIds.First().Key).hello("Send to only(also first) one");
}
else
{
Clients.Clients(allExceptLast).hello("Send to everyone except last");
Clients.Client(lastConnection.Key).hello("Send to only the last one");
}
});
task.ContinueWith(base.OnConnected());
return task;
}
I haven't tested that... its just a guess..
My server-sent events are not sending anymore. This use to work perfectly and now something has changed and it might be that I am running this as an ASP.Net 4 application. I'm using a pretty standard iHTTPRequest Handler with a loop, a little threading timeout, and around I go, writing messages like this:
A Message - Note: the reason for parsing the message the way I do below, is I wasn't sure if there was a max message length, so in order to elminate this as a potential problem I broke it out. Well forget this bit anyways, because I'm testing now with the most basic message "alive" so it never hits this.
public static void WriteClientMessage(this HttpResponse Response, string Message)
{
if (Message.Length > 50)
{
int start = 0;
int length = 50;
while (length > 0)
{
Response.Write("data: {0}\n", Message.Substring(start, length));
start = start + length;
length = Message.Substring(start, (Message.Substring(start).Length >= length) ? length : Message.Substring(start).Length).Length;
}
}
else
{
Response.Write("data: " + Message);
Response.Write("\n");
}
Response.Write("\n");
Response.Flush();
}
An Event
public static void WriteClientEvent(this HttpResponse Response, string EventName)
{
Response.Write("event: {0}\n", EventName.TrimNewLine());
Response.Write("data: \n\n");
Response.Flush();
}
Something else to note and I think this is really important is that eventually the message do come, but they come all at once, as if they are buffered. So I've played with this, both enable and disable buffering. I've even investigated to make sure that my dynamic content isn't being compressed, although I'm not confident I have this right, but pretty sure that it isn't. I will investigate this further if someone says that for sure it is and this is my problem
So what is it? Is this a .Net 4ism?
**UPDATE - Insert Minimal Sample here - **
I've added a sample of the script here: http://live.meetscoresonline.com/test-sse.aspx
This app loops 10 times and then breaks out of the loop. This is the actual SSE service, so you should get the result directly to your browser, at least in chrome, FF tries to download the file, and haven't tested the other browsers. What I expect to see is data: alive to apear in the browser as it happens, instead nothing appears until the script terminates and then all data: alive events appear. I've tested SSE this way before so I know this works (or use to work). Here is this test code. Am I missing something?
UPDATE: I commented out the break to demonstrate a new behavior. If you wait about 20 or 30 loops, the real-time streaming begins and continues as expected. So what is this initial pause?
public class TestSSE : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/event-stream";
var itt = 0; ;
while (true)
{
if (!context.Response.IsClientConnected)
break;
/* **** UPDATE: REMOVED THE BREAK. STREAMING BEGINS AFTER ABOUT THE 20TH OR 30TH LOOP ****/
// if (itt++ > 10)
// break;
context.Response.Write("data: alive {0}\n\n", DateTime.Now.ToLongTimeString());
context.Response.Flush();
System.Threading.Thread.Sleep(2000);
}
}
}
Looking at the Network tab in Google Chrome developer tools reveals quite a lot from your http://live.meetscoresonline.com/test-sse.aspx
There are no SSE being generated at all - to see this click on the Others button under Network, this is where you would normally be able to track the SSE data stream
I use the following code in my SSE's with a simple HTTPListener and it works well without the delays you mentioned, and always shows up correctly across browsers when using this polyfill
res.AddHeader("Content-Type", "text/event-stream")
res.AddHeader("Cache-Control", "no-cache")
res.AddHeader("Access-Control-Allow-Origin", "*")
res.KeepAlive = True