I am struggling on how to get the text of a message to my C#-console tool with a telegram bot. Here is a piece of that is supposed to just print all messages in the telegram channel
private async Task getTelegramMessage()
{
var bot = new Telegram.Bot.TelegramBotClient("token")
var updates = await bot.GetUpdatesAsync();
foreach (var update in updates)
{
Console.WriteLine("Bot: " + update.Message.Text);
}
}
the problem is that i always get all old updates. The maximum length of the array updates is 100. So after I sent 100 messages in the telegram channel, I would only have access to the first 100 messages and no access to the newest. How can I get access to the most recent update? Or can I somehow delete the message after my tool has processed it?
I have seen that the bot provides the Event OnUpdate but I couldnt figure out how to use it.
Thanks a lot for help on that issue.
According documentation, you can use offset -1 to get the last update.
Just put in mind all previous updates will forgotten.
getUpdates Docs
https://api.telegram.org/bot{TOKEN}/getUpdates?offset=-1
oh, I just figured it out. for the offset you have to set the ID returned in the update.
Notes
2. In order to avoid getting duplicate updates, recalculate offset after each server response.
Instead subscribe to the BotOnUpdateReceived event to handle the updates. In main.cs:
Bot.OnUpdate += BotOnUpdateReceived;
Bot.StartReceiving(Array.Empty<UpdateType>());
Console.WriteLine($"Start listening!!");
Console.ReadLine();
Bot.StopReceiving();
And handle the event:
private static async void BotOnUpdateReceived(object sender, UpdateEventArgs e)
{
var message = e.Update.Message;
if (message == null || message.Type != MessageType.Text) return;
var text = message.Text;
Console.WriteLine(text);
await Bot.SendTextMessageAsync(message.Chat.Id, "_Received Update._", ParseMode.Markdown);
}
The Offset is internally working in it and it also internally call GetUpdatesAsync().
From Here you can also get channel post via:
var message = e.Update.ChannelPost.Text; // For Text Messages
I hope it will Help!!
Related
private async void CharacteristicReadButton_Click()
{
// BT_Code: Read the actual value from the device by using Uncached.
GattReadResult result = await selectedCharacteristic.ReadValueAsync(BluetoothCacheMode.Uncached);
if (result.Status == GattCommunicationStatus.Success)
{
string formattedResult = FormatValueByPresentation(result.Value, presentationFormat);
rootPage.NotifyUser($"Read result: {formattedResult}", NotifyType.StatusMessage);
}
else
{
rootPage.NotifyUser($"Read failed: {result.Status}", NotifyType.ErrorMessage);
}
}
I'm facing a problem with the read value change. I have setup mpu5060 with my rfduino, so whenever my rfduino moved, it will display the angle on my Arduino serial monitor.
for my c#, I can read the value when I press the "read" button. But if my value(angle) change, it will not auto update to notify user. I have to manually click the "read" button again to change. How do I make it auto update ?
you need to create timer thread to monitor changing of your value.
see this
Timer class
Why not setting up your RfDuino to send a notification, if that is possible.
Or even add your data as advertising, then there is no need for a connection, just reed in in OnAdvertisementReceived.
In your RfDuino do it like this:
void advertise(const char *data, uint32_t ms)
{
// this is the data we want to appear in the advertisement
// /make sure that the RfDuino name + data is not more than 31 bytes
RFduinoBLE.advertisementData = data;
// start the BLE stack
RFduinoBLE.begin();
// advertise for ms milliseconds
RFduino_ULPDelay(ms);
// stop the BLE stack
RFduinoBLE.end();
}
If you want to send new data call:
// advertise "data" for indicated time
advertise("your data", duration);
I'm using Discord.Net in C#, making a bot. My bot works fantastic so far, but I want it to automatically assign users a specific role when they join a specific server. I've never actually learned any C#, only a bit of C++ so I know the basic Grammar. How would I go about this?
I'm assuming I would use UserJoined, but doing this heeds results telling me to use it before or after a += or -+ (Which I understand, but I don't understand it's usefullness in this given scenario)
You gave little information to work with but here is how to do it in all releases (so far):
This is IN the dependency map but below the "handlecommand", CommandHandleAsync or HandleCommandAsync:
client.UserJoined += AnnounceJoinedUser; //Hook into the UserJoined event of the client.
This is under the dependency map:
public async Task AnnounceJoinedUser(SocketGuildUser user) //Welcomes the new user
{
var channel = client.GetChannel(/*/TextChannelID/*/) as SocketTextChannel; // Gets the channel to send the message in
await channel.SendMessageAsync($"Welcome {user.mention} to {channel.Guild.Name}"); //Welcomes the new user
}
In case any of you wanted to send a message directly to the joining user
client.UserJoined += HandleUserJoinedAsync;
private async Task HandleUserJoinedAsync(SocketGuildUser gUser)
{
if (gUser.IsBot || gUser.IsWebhook) return;
var dmChannel = await gUser.GetOrCreateDMChannelAsync();
await dmChannel.SendMessageAsync("Witaj");
}
For all those who need an answer, in this period, I leave you this piece of code, just to send a message to a user's join, (1 line):
Client.UserJoined += join;
private async Task join(SocketGuildUser user)
{
await (user.Guild.DefaultChannel).SendMessageAsync("Text")
return;
}
I'm not much of a coder or anything I'm just doing this for fun!
A server I am in with some friends needed a bot, there's of course a ton of bots available but I thought I'd go ahead and try my luck at making my own. I know some basic code and I've written a simple bot in C#, but for the life of me I cannot figure out how to make a purge command.
What I currently have created is this:
RegisterPurgeCommand();
private void RegisterPurgeCommand()
{
commands.CreateCommand("purge")
.Parameter("PurgeAmount")
.Do(async (e) =>
{
var messagesToDelete = await e.Channel.DownloadMessages(convert.ToInt32(e.GetArg("purgeAmount")));
await e.Channel.DeleteMessages(messagesToDelete);
await e.Channel.SendMessage(e.GetArg("purgeAmount") + "Messages Deleted.");
});
}
You can view the code here in screenshot format if you prefer
What I initially had was a purge command that deleted messages by x amount in the code, not by the amount I want. For example, what my goal is that in Discord I will do something along the lines of !purge 10 and the last 10 messages are deleted. What I previously had was a !purge command that deleted the previous 10 messages, but if I wanted to do 7 for example, it would still do 10.
The code for that, is:
RegisterPurgeCommand();
private void RegisterPurgeCommand()
{
commands.CreateCommand("purge")
.Do(async (e) =>
{
Message[] messagesToDelete;
messagesToDelete = await e.Channel.DownloadMessages(100);
await e.Channel.DeleteMessages(messagesToDelete);
});
}
you can view the code here in screenshot format if you prefer
this worked fine, but as I said wasn't really efficient.
Now, I'll be completely honest and say that the the method I'm using now (the one that isn't working) is off of an explanation on Gist.
So what it currently does is... Absolutely nothing.. What it used to do is delete x amount of messages that I told it to delete in the code so for example if I wanted to remove 7 messages in the server it would delete 10.
What I want it do is that I can tell the bot to remove x amount of messages in the server regardless by its amount, not that if I want to remove 7 that it removes 10.
Maybe I'm missing something very easily? Maybe I'm just overlooking something stupid? I am legit lost. It is also 6 in the morning as I'm writing this, so it may be that aswell.
You are parsing a Parameter PurgeAmount but not actually using it for anything.
messagesToDelete = await e.Channel.DownloadMessages(100);
On this line instead of using 100, use your purge amount parameter
EDIT with my version:
So this is how I did it, ignore the console stuff thats just debugging.
Console.WriteLine(_channel.Users);
var userPermissions = _user.GetPermissions(_channel).ManageMessages;
Console.WriteLine("Admin" + userPermissions);
int number = int.Parse(_parameter);
Message[] message = new Message[number];
message = _channel.DownloadMessages(number).Result;
if (userPermissions == true)
{
_channel.DeleteMessages(message);
Console.WriteLine("Channel Admin: " + _user + " deleted messages from the channel: " + _channel);
}
else
{
Console.WriteLine("User: " + _user + " tried to delete messages from: #" + _channel + " when they aren't an admin there.");
}
I have 1 exe which is nothing bit a Windows form which will continuously run in background and will watch my serial port and I have 1 event data receive event which fires as my serial port receive data.
As soon as I receive data in this event I will pass this data to another event handler which saves this data in database through web api method.
But data to my serial port will be coming frequently so I want to save this data to my database independently so that my database insert operation doesn't block my incoming serial port data.
This is my code:
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)//Fires as my serial port receives data
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
// Send data to whom ever interested
if (NewSerialDataRecieved != null)
{
NewSerialDataRecieved(this, new SerialDataEventArgs(data)); //pass serial port data to new below event handler.
}
}
void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e) //I want this event handler to run independently so that database save operation doenst block incoming serial port data
{
if (this.InvokeRequired)
{
// Using this.Invoke causes deadlock when closing serial port, and BeginInvoke is good practice anyway.
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved), new object[] { sender, e });
return;
}
//data is converted to text
string str = Encoding.ASCII.GetString(e.Data);
if (!string.IsNullOrEmpty(str))
{
//This is where i will save data to through my web api method.
RunAsync(str).Wait();
}
}
static async Task RunAsync(string data)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:33396/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = new StringContent(data);
var response = await client.PostAsJsonAsync<StringContent>("api/Service/Post", content);//nothing happens after this line.
}
}
Web api controller:
public class MyController : ApiController
{
[HttpPost]
public HttpResponseMessage Post(HttpRequestMessage request)
{
var someText = request.Content.ReadAsStringAsync().Result;
return new HttpResponseMessage() { Content = new StringContent(someText) };
}
}
But here problem is:
var response = await client.PostAsJsonAsync<StringContent>("api/Service/Post", content);
Nothing happens after this line that is operation blocks on this line.
So can anybody guide me with this?
By independently we determined in the SO C# chat room that you really mean "Asynchronously".
Your solution is the code above, saving this data to a WebAPI endpoint so any solution to the problem needs to be in 2 parts ...
PART 1: The Client Part
On the client all we need to do is make the call asynchronously in order to free up the current thread to carry on receiving data on the incoming serial port, we can do that like so ...
// build the api client, you may want to keep this in a higher scope to avoid recreating on each message
var api = new HttpClient();
api.BaseAddress = new Uri(someConfigVariable);
// asynchronously make the call and handle the result
api.PostAsJsonAsync("api/My", str)
.ContinueWith(t => HandleResponseAsync(t.Result))
.Unwrap();
...
PART 2: The Server Part
Since you have web api i'm also going to assume you are using EF too, the common and "clean" way to do this, with all the extras stripped out (like model validation / error handling) might look something like this ...
// in your EF code you will have something like this ...
Public async Task<User> SaveUser(User userModel)
{
try
{
var newUser = await context.Users.AddAsync(userModel);
context.SavechangesAsync();
return newUser;
}
catch(Exception ex) {}
}
// and in your WebAPI controller something like this ...
HttpPost]
public async Task<HttpResponseMessage> Post(User newUser)
{
return Ok(await SaveUser(newUser));
}
...
Disclaimer:
The concepts involved here go much deeper and as I hinted above, much has been left out here like validation, error checking, ect but this is the core to getting your serial port data in to a database using the technologies I believe you are using.
Key things to read up on for anyone wanting to achieve this kind of thing might include: Tasks, Event Handling, WebAPI, EF, Async operations, streaming.
From what you describe it seems like you might want to have a setup like this:
1) your windows form listens for serial port
2) when new stuff comes to port your windows forms app saves it to some kind of a queue (msmq, for example)
3) you should have separate windows service that checks queue and as it finds new messages in a queue it sends request to web api
Best solution for this problem is to use ConcurrentQueue.
Just do search on google and you will get planty of samples.
ConcurrentQueue is thread safe and it support writing and reading from multiple threads.
So the component listening to the searal port can write data to the queue. And you can have 2 or more tasks running parallel which listening to this queue and update db as soon as it receives data.
Not sure if it's the problem, but you shouldn't block on async code. You are doing RunAsync(str).Wait(); and I believe that's the problem. Have a look at this blog post by Stephen Cleary:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
I have a message queue where i add some emails.
I want to extract all emails, examine the date when they were added and their priority and send only one of them.
I read messages like this:
private IList<Email> GetEmailsFromQueue(MessageQueue queue)
{
queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(Email) });
IList<Email> emails = new List<Email>();
Cursor cursor = queue.CreateCursor();
Message m = PeekWithoutTimeout(queue, cursor, PeekAction.Current);
if (m != null)
{
emails.Add((Email)m.Body);
while ((m = PeekWithoutTimeout(queue, cursor, PeekAction.Next)) != null)
{
emails.Add((Email)m.Body);
}
}
return emails;
}
private Message PeekWithoutTimeout(MessageQueue q, Cursor cursor, PeekAction action)
{
Message msgFromQueue = null;
try
{
msgFromQueue = q.Peek(new TimeSpan(1), cursor, action);
}
catch(MessageQueueException ex)
{
if (!ex.Message.ToLower().Contains("timeout"))
{
throw;
}
}
return msgFromQueue;
}
Receive method will remove the message from the queue.
Is there any way to read and remove only some messages?
LE: One solution i mighty think of is to add an id to each message, and use ReceiveById
Any other tips?
Is there any way to read and remove only some messages?
I've never used MSMQ (well not in anger anyways) but I think you should be able to combine both the Peek and ReceiveById methods.
So you would continue to Peek at the queue to see what messages are available and then once you have decided to remove a message make use of the ReceiveById, to process/remove from the queue.
Aside from this perhaps the other option would be to make use of 2 queues. The first would be for all inbound messages and the second would be used to add back messages you want to keep.
So going back to your example (assuming I understand what you're trying to achieve)
the first would be for inbound emails which you process as described extract all emails, examine the date when they were added and their priority
the second would be for your outbound emails i.e. once you have the email you want to send, push it on to the outbound queue