I'm making a Discord bot and there's a channel in my server allocated to our rules and I want this bot to automatically send a message in that channel. Is it possible to check if the channel exists? Thanks.
Yes you definitely can.
if (message.Content.StartsWith("!check"))
{
SocketGuildChannel currentChannel = message.Channel as SocketGuildChannel;
SocketGuild guild = currentChannel.Guild;
foreach (SocketGuildChannel ch in guild.Channels)
{
if (ch.GetType() == typeof(SocketTextChannel)) //Checking text channels
{
if (ch.Name.Equals("rules"))
{
ISocketMessageChannel channel = (ISocketMessageChannel)ch; //Casting so we can send a message
await channel.SendMessageAsync("This is the rules channel.");
return;
}
}
}
await message.Channel.SendMessageAsync("Could not find the rules channel.");
return;
}
Assuming you are using Discord.Net 1.0.2
If you want to have it as a command:
[Command("check")]
public async Task CheckChannel(string channel)
{
foreach (SocketGuildChannel chan in Context.Guild.Channels)
{
if (channel == chan.Name)
{
// It exists!
ITextChannel ch = chan as ITextChannel;
await ch.SendMessageAsync("This is the rules channel!");
}
else
{
// It doesn't exist!
await ReplyAsync($"No channel named {channel} was found.");
}
}
}
You could also use Linq!
[Command("check")]
public async Task CheckChannel(string channelName)
{
//Makes the channel name NOT case sensitive
var channel = Context.Guild?.Channels.FirstOrDefault(c => string.Equals(c.Name, channelName, StringComparison.OrdinalIgnoreCase));
if (channel != null)
{
ITextChannel ch = channel as ITextChannel;
await ch.SendMessageAsync("This is the rules channel!");
}
else
{
// It doesn't exist!
await ReplyAsync($"No channel named {channel} was found.");
}
}
Also a warning, This will fail in a DM because Context.Guild == null in a direct message. If you so desired, you can add this snippet inside your command!
if (Context.IsPrivate)
{
await ReplyAsync("Cant call command from a direct message");
return;
}
Related
In my case I want to send the message to all sessions not only user (user can have many sessions), I used foreach to send message to all connections belong to friends with its others sessions,
there is a problem in await asynchronous and a message:
Failed writing message. Aborting connection. System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 64. Consider using ReferenceHandler.Preserve on JsonSerializerOption
// Test if the user is offline :
// Find My opened sessions and target opened sessions
if (userInfoReciever != null)
{
var targetSessions = _context.Connections.Where(C => (C.Username == targetUserModel.UserName) && (C.Connected == true)).ToList();
if (targetSessions != null)
{
foreach (var targetSeesion in targetSessions)
{
await Clients.Client(targetSeesion.ConnectionID).SendAsync("SendDM", messageModel, userInfoSender);
await Clients.Client(targetSeesion.ConnectionID).SendAsync("SendDN", notificationModel, userInfoSender);
}
}
}
await Clients.Caller.SendAsync("MyMessage", messageModel, userInfoSender);
if (userInfoSender != null)
{
var mySessions = _context.Connections.Where(C => ((C.ConnectionID != Context.ConnectionId) && (C.Username == Context.User.Identity.Name) && (C.Connected == true))).ToList();
if (mySessions != null)
{
foreach(var mySession in mySessions)
{
await Clients.Client(mySession.ConnectionID).SendAsync("MyMessage", messageModel, userInfoSender);
}
}
}
// Send my message to the the others sessions :
// Build the message
var _message = _mapper.Map<MessageViewModel,Message>(messageModel);
var _notification = _mapper.Map<NotificationViewModel, Notification>(notificationModel);
await _context.Messages.AddAsync(_message);
await _context.Notifications.AddAsync(_notification);
await _context.SaveChangesAsync();
I am trying to create a discord bot using DSharpPlus library where if you react on a message with specific emoji, you will get a specific role. The concept is pretty straight forward but I fail to figure out one rather important concept. That is, how do I get the bot to listen for a reaction on an existing message all the time.
I tried to do it via commands and I got it to work, however the problem with this approach as I learned is that the bot only listens for reactions after I type a command and it only lasts a minute or so (based on configuration).
public class RoleCommands : BaseCommandModule
{
[Command("join")]
public async Task Join(CommandContext ctx)
{
var joinEmbed = new DiscordEmbedBuilder
{
Title = "Reaction with thumbs up!",
Color = DiscordColor.Green
};
var joinMessage = await ctx.Channel.SendMessageAsync(embed: joinEmbed).ConfigureAwait(false);
var thumbsUpEmoji = DiscordEmoji.FromName(ctx.Client, ":+1:");
var thumbsDownEmoji = DiscordEmoji.FromName(ctx.Client, ":-1:");
await joinMessage.CreateReactionAsync(thumbsUpEmoji).ConfigureAwait(false);
await joinMessage.CreateReactionAsync(thumbsDownEmoji).ConfigureAwait(false);
var interactivity = ctx.Client.GetInteractivity();
var reactionResult = await interactivity.WaitForReactionAsync(x =>
x.Message == joinMessage
&& x.User == ctx.User
&& x.Emoji == thumbsUpEmoji);
if (reactionResult.Result.Emoji == thumbsUpEmoji)
{
var role = ctx.Guild.GetRole(773965440913375282);
await ctx.Member.GrantRoleAsync(role).ConfigureAwait(false);
await joinMessage.DeleteAsync().ConfigureAwait(false);
}
}
}
How can I do this outside of a command where I can pass it a message Id and then it listens to that message for reactions all the time as oppose to a limited time?
The full answer to my question is to use DiscordClient.MessageReactionAdded += OnReactionAdded; and to implement the method as such:
private async Task OnReactionAdded(DiscordClient sender, MessageReactionRemoveEventArgs e)
{
var messageId = e.Message.Id;
var guild = e.Message.Channel.Guild;
var reactionName = e.Emoji.GetDiscordName();
var reactionDetail = ReactionDetails.FirstOrDefault(x =>
x.MessageId == messageId
&& x.GuildId == guild.Id
&& x.ReactionName == reactionName);
if (reactionDetail != null)
{
var member = e.User as DiscordMember;
if (member != null)
{
var role = guild.Roles.FirstOrDefault(x => x.Value.Id == reactionDetail.RoleId).Value;
await member.GrantRoleAsync(role).ConfigureAwait(false);
}
}
}
Store the message id somewhere then hook the MessageReactionAdded event on your DiscordClient and do your logic there.
I’ m currently debugging a webrtc UWP app, and it is fairly working.
But it happens that the remote stream is not displayed on my MediaElement each time. It’s like the video track is not received although I add it ASAP as recommended. I can’t figure out why it is happening ; is it a code or a network problem ? I grab the stream randomly whatever the network, sometimes successfully, other times not (staying with the same confits).
I use the google STUN servers, and the google webrtc « peer connection server » signaling server on a remote windows server, nothing is installed on my LAN (but my UWP program).
I don’t know what to do to figure out the cause ... any help would be appreciated.
private void Signaller_OnMessageFromPeer(int peerId, string message)
{
Task.Run(async () =>
{
// Debug.Assert(_peerId == peerId || _peerId == -1);
Debug.Assert(message.Length > 0);
if (_peerId != peerId && _peerId != -1)
{
Debug.WriteLine("[Error] Conductor: Received a message from unknown peer while already in a conversation with a different peer.");
return;
}
if (!JsonObject.TryParse(message, out JsonObject jMessage))
{
Debug.WriteLine("[Error] Conductor: Received unknown message." + message);
return;
}
string type = jMessage.ContainsKey(kSessionDescriptionTypeName) ? jMessage.GetNamedString(kSessionDescriptionTypeName) : null;
if (_peerConnection == null)
{
if (!String.IsNullOrEmpty(type))
{
// Create the peer connection only when call is
// about to get initiated. Otherwise ignore the
// messages from peers which could be a result
// of old (but not yet fully closed) connections.
if (type == "offer" || type == "answer")
{
Debug.Assert(_peerId == -1);
_peerId = peerId;
connectToPeerCancelationTokenSource = new CancellationTokenSource();
connectToPeerTask = CreatePeerConnection(connectToPeerCancelationTokenSource.Token);
bool connectResult = await connectToPeerTask;
connectToPeerTask = null;
connectToPeerCancelationTokenSource.Dispose();
if (!connectResult)
{
Debug.WriteLine("[Error] Conductor: Failed to initialize our PeerConnection instance");
await Signaller.SignOut();
return;
}
else if (_peerId != peerId)
{
Debug.WriteLine("[Error] Conductor: Received a message from unknown peer while already in a conversation with a different peer.");
return;
}
}
}
else
{
Debug.WriteLine("[Warn] Conductor: Received an untyped message after closing peer connection.");
return;
}
}
if (!String.IsNullOrEmpty(type))
{
if (type == "offer-loopback")
{
// Loopback not supported
Debug.Assert(false);
}
string sdp = jMessage.ContainsKey(kSessionDescriptionSdpName) ? jMessage.GetNamedString(kSessionDescriptionSdpName) : null;
if (String.IsNullOrEmpty(sdp))
{
Debug.WriteLine("[Error] Conductor: Can't parse received session description message.");
return;
}
RTCSdpType sdpType = RTCSdpType.Offer;
switch (type)
{
case "offer":
sdpType = RTCSdpType.Offer;
break;
case "answer":
sdpType = RTCSdpType.Answer;
break;
case "pranswer":
sdpType = RTCSdpType.Pranswer;
break;
default:
Debug.Assert(false, type);
break;
}
Debug.WriteLine("Conductor: Received session description: " + message + "\r\n" + sdp);
await _peerConnection.SetRemoteDescription(new RTCSessionDescription(sdpType, sdp));
if (sdpType == RTCSdpType.Offer)
{
RTCSessionDescription answer = await _peerConnection.CreateAnswer();
await _peerConnection.SetLocalDescription(answer);
// Send answer
SendSdp(answer);
Debug.WriteLine(String.Format("Conductor: Session Description to be sent : {0}", answer.Sdp));
}
}
else
{
var sdpMid = jMessage.ContainsKey(kCandidateSdpMidName) ? jMessage.GetNamedString(kCandidateSdpMidName) : null;
var sdpMlineIndex = jMessage.ContainsKey(kCandidateSdpMlineIndexName) ? jMessage.GetNamedNumber(kCandidateSdpMlineIndexName) : -1;
var sdp = jMessage.ContainsKey(kCandidateSdpName) ? jMessage.GetNamedString(kCandidateSdpName) : null;
if (String.IsNullOrEmpty(sdpMid) || sdpMlineIndex == -1 || String.IsNullOrEmpty(sdp))
{
Debug.WriteLine("[Error] Conductor: Can't parse received message.\n" + message);
return;
}
var candidate = new RTCIceCandidate(sdp, sdpMid, (ushort)sdpMlineIndex);
await _peerConnection.AddIceCandidate(candidate);
Debug.WriteLine("Conductor: Received candidate : " + message);
}
}).Wait();
}
Hi I created my first test bot using Microsoft BotFramework in C#.
in private async Task< Activity > HandleSystemMessage(Activity message) in if (message.Type == ActivityTypes.ConversationUpdate) normally it should notify a new member added to group or someone hit the start button of bot in Telegram Messenger. When I test it in debug mode using BotFramework emulator everything works perfectly but after I publish it I see that after hitting start button in Telegram messenger my code didn't run.
My code in ActivationType.ConversationUpdate
foreach (var item in message.MembersAdded)
{
try
{
using (var dbcontext = new WatermarkBotDBEntities())
{
dbcontext.BotUsers.Add(new BotUser()
{
AddedFriends = 0,
ConversationID = message.Conversation.Id,
ServiceUrl = message.ServiceUrl,
UserID = message.From.Id
});
dbcontext.SaveChanges();
if (Request.RequestUri.Query != "")
{
var u = dbcontext.BotUsers.Where(x => x.BotSalCode == Request.RequestUri.Query.Replace("?start=", string.Empty)).FirstOrDefault();
u.AddedFriends++;
dbcontext.Entry(u).State = System.Data.Entity.EntityState.Modified;
if (u != null)
{
var connector = new ConnectorClient(new Uri(u.ServiceUrl));
IMessageActivity newMessage = Activity.CreateMessageActivity();
newMessage.Type = ActivityTypes.Message;
//newMessage.From = new ChannelAccount("<BotId>", "<BotName>");
newMessage.From = new ChannelAccount("c3e7mhdafcecn7ng3", "Bot");
newMessage.Conversation = new ConversationAccount(false, u.ConversationID);
newMessage.Recipient = new ChannelAccount(u.UserID);
if (u.AddedFriends <= 2)
newMessage.Text = $"SomeText.";
else newMessage.Text = "SomeTex";
await connector.Conversations.SendToConversationAsync((Activity)newMessage);
dbcontext.SaveChanges();
}
}
}
}
catch (Exception ex)
{
}
So how is it possible to detect hitting start in telegram ?
Regards
I realize this is not a complete answer, but I wanted to share this code with you in case it may help. Below is the recommended way to send a welcome message, you may be able to repurpose this code for your use.
else if (message.Type == ActivityTypes.ConversationUpdate || message.Type == ActivityTypes.Message)
{
IConversationUpdateActivity iConversationUpdated = message as IConversationUpdateActivity;
if (iConversationUpdated != null)
{
ConnectorClient connector = new ConnectorClient(new System.Uri(message.ServiceUrl));
foreach (var member in iConversationUpdated.MembersAdded ?? System.Array.Empty<ChannelAccount>())
{
// if the bot is added, then
if (member.Id == iConversationUpdated.Recipient.Id)
{
var reply = ((Activity)iConversationUpdated).CreateReply(
$"Hi! I'm Botty McBot.");
await connector.Conversations.ReplyToActivityAsync(reply);
}
}
}
}
This is the answer I found for my question after lots of testing :
In MessagesController class in public async Task<HttpResponseMessage> Post([FromBody]Activity activity) function that defined by default in a BotFramework Application you have to do something like this :
if (activity.Type == ActivityTypes.Message)
{
if (activity.Text.StartsWith("/start"))
{
//This will return you the start parameter of a link like : http://telegram.me/botname?start=Parameter
var Parameter = activity.Text.Replace("/start ", "");
}
}
and if you want to send a welcome message so you can surely use the way that #JasonSowers told and use his code to send your message .
Best Regards
I configure the server as following on startup.cs
GlobalHost.HubPipeline.RequireAuthentication();
// Make long polling connections wait a maximum of 110 seconds for a
// response. When that time expires, trigger a timeout command and
// make the client reconnect.
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(40);
// Wait a maximum of 30 seconds after a transport connection is lost
// before raising the Disconnected event to terminate the SignalR connection.
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(30);
// For transports other than long polling, send a keepalive packet every
// 10 seconds.
// This value must be no more than 1/3 of the DisconnectTimeout value.
GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(10);
GlobalHost.HubPipeline.AddModule(new SOHubPipelineModule());
var hubConfiguration = new HubConfiguration { EnableDetailedErrors = true };
var heartBeat = GlobalHost.DependencyResolver.Resolve<ITransportHeartbeat>();
var monitor = new PresenceMonitor(heartBeat);
monitor.StartMonitoring();
app.MapSignalR(hubConfiguration);
where PresenceMonitor is the class responsible of check unlive data . as I keep them in database using the following code
public class PresenceMonitor
{
private readonly ITransportHeartbeat _heartbeat;
private Timer _timer;
// How often we plan to check if the connections in our store are valid
private readonly TimeSpan _presenceCheckInterval = TimeSpan.FromSeconds(40);
// How many periods need pass without an update to consider a connection invalid
private const int periodsBeforeConsideringZombie = 1;
// The number of seconds that have to pass to consider a connection invalid.
private readonly int _zombieThreshold;
public PresenceMonitor(ITransportHeartbeat heartbeat)
{
_heartbeat = heartbeat;
_zombieThreshold = (int)_presenceCheckInterval.TotalSeconds * periodsBeforeConsideringZombie;
}
public async void StartMonitoring()
{
if (_timer == null)
{
_timer = new Timer(_ =>
{
try
{
Check();
}
catch (Exception ex)
{
// Don't throw on background threads, it'll kill the entire process
Trace.TraceError(ex.Message);
}
},
null,
TimeSpan.Zero,
_presenceCheckInterval);
}
}
private async void Check()
{
// Get all connections on this node and update the activity
foreach (var trackedConnection in _heartbeat.GetConnections())
{
if (!trackedConnection.IsAlive)
{
await trackedConnection.Disconnect();
continue;
}
var log = AppLogFactory.Create<WebApiApplication>();
log.Info($"{trackedConnection.ConnectionId} still live ");
var connection = await (new Hubsrepository()).FindAsync(c => c.ConnectionId == trackedConnection.ConnectionId);
// Update the client's last activity
if (connection != null)
{
connection.LastActivity = DateTimeOffset.UtcNow;
await (new Hubsrepository()).UpdateAsync(connection, connection.Id).ConfigureAwait(false);
}
}
// Now check all db connections to see if there's any zombies
// Remove all connections that haven't been updated based on our threshold
var hubRepository = new Hubsrepository();
var zombies =await hubRepository.FindAllAsync(c =>
SqlFunctions.DateDiff("ss", c.LastActivity, DateTimeOffset.UtcNow) >= _zombieThreshold);
// We're doing ToList() since there's no MARS support on azure
foreach (var connection in zombies.ToList())
{
await hubRepository.DeleteAsync(connection);
}
}
}
and my hub connect disconnect , reconnect looks like
public override async Task OnConnected()
{
var log = AppLogFactory.Create<WebApiApplication>();
if (Context.QueryString["transport"] == "webSockets")
{
log.Info($"Connection is Socket");
}
if (Context.Headers.Any(kv => kv.Key == "CMSId"))
{
// Check For security
var hederchecker = CryptLib.Decrypt(Context.Headers["CMSId"]);
if (string.IsNullOrEmpty(hederchecker))
{
log.Info($"CMSId cannot be decrypted {Context.Headers["CMSId"]}");
return;
}
log.Info($" {hederchecker} CMSId online at {DateTime.UtcNow} ");
var user = await (new UserRepository()).FindAsync(u => u.CMSUserId == hederchecker);
if (user != null)
await (new Hubsrepository()).AddAsync(new HubConnection()
{
UserId = user.Id,
ConnectionId = Context.ConnectionId,
UserAgent = Context.Request.Headers["User-Agent"],
LastActivity = DateTimeOffset.UtcNow
}).ConfigureAwait(false);
//_connections.Add(hederchecker, Context.ConnectionId);
}
return;
}
public override async Task OnDisconnected(bool stopCalled)
{
try
{
//if (!stopCalled)
{
var hubRepo = (new Hubsrepository());
var connection = await hubRepo.FindAsync(c => c.ConnectionId == Context.ConnectionId);
if (connection != null)
{
var user = await (new UserRepository()).FindAsync(u => u.Id == connection.UserId);
await hubRepo.DeleteAsync(connection);
if (user != null)
{
//var log = AppLogFactory.Create<WebApiApplication>();
//log.Info($"CMSId cannot be decrypted {cmsId}");
using (UserStatusRepository repo = new UserStatusRepository())
{
//TODO :: To be changed immediatley in next release , Date of change 22/02/2017
var result = await (new CallLogRepository()).CallEvent(user.CMSUserId);
if (result.IsSuccess)
{
var log = AppLogFactory.Create<WebApiApplication>();
var isStudent = await repo.CheckIfStudent(user.CMSUserId);
log.Info($" {user.CMSUserId} CMSId Disconnected here Before Set offline at {DateTime.UtcNow} ");
var output = await repo.OfflineUser(user.CMSUserId);
log.Info($" {user.CMSUserId} CMSId Disconnected here after Set offline at {DateTime.UtcNow} ");
if (output)
{
log.Info($" {user.CMSUserId} CMSId Disconnected at {DateTime.UtcNow} ");
Clients.All.UserStatusChanged(user.CMSUserId, false, isStudent);
}
}
}
}
}
}
}
catch (Exception e)
{
var log = AppLogFactory.Create<WebApiApplication>();
log.Error($"CMSId cannot Faild to be offline {Context.ConnectionId} with error {e.Message}{Environment.NewLine}{e.StackTrace}");
}
}
public override async Task OnReconnected()
{
string name = Context.User.Identity.Name;
var log = AppLogFactory.Create<WebApiApplication>();
log.Info($" {name} CMSId Reconnected at {DateTime.UtcNow} ");
var connection = await (new Hubsrepository()).FindAsync(c => c.ConnectionId == Context.ConnectionId);
if (connection == null)
{
var user = await (new UserRepository()).FindAsync(u => u.CMSUserId == name);
if (user != null)
await (new Hubsrepository()).AddAsync(new HubConnection()
{
UserId = user.Id,
ConnectionId = Context.ConnectionId,
UserAgent = Context.Request.Headers["User-Agent"],
LastActivity = DateTimeOffset.UtcNow
}).ConfigureAwait(false);
}
else
{
connection.LastActivity = DateTimeOffset.UtcNow;
await (new Hubsrepository()).UpdateAsync(connection, connection.Id).ConfigureAwait(false);
}
}
all test cases passes well except when internet cut on client side the connection keep live for more than 10 minutes, is this related to authentication , or any configuration wrong at my side any help am really don't know what's wrong . client use websocket transport