Discord.NET Guild.DefaultChannel does not work - c#

I am coding a discord bot, and I want it to send a message to a server default channel whenever the bot joins a new server.
Here is my code
client.JoinedGuild += async guild =>
{
var channel = guild.DefaultChannel;
await channel.SendMessageAsync("test");
};
The error occurs on channel.SendMessageAsync, and when I debugged the program, it keeps showing that channel is null even though I do have a default channel in my server.

A discord update months ago removed defaultChannel property. Which means that servers now do not need to have a default channel at all.
(You can even delete all channel in your server!)
Which also means Guild.DefaultChannel property will not work as intended anymore.
(Correct me if I am wrong, but if a server still has a #general channel, the property will work as intended.)
Discord.NET v2+ have a working DefaultChannel property. (It uses its own set of algorithm to determine which would be the default channel for the guild.)
The source code for the algorithm is here. (Line 66-69)
Looking at the algorithm, you may want to be slightly cautious about using it, if your bot have permission to send messages everywhere, the DefaultChannel property would simply be the first channel in the server's channel list.
(And it would be bad news if that was a readme channel)

Related

LDAP - What to use instead of DirSyncRequestControl

I'm migrating some code away from Active Directory re-writing all directory requests to reference classes in System.Directory.Protocols and be LDAP v3 compliant. This is supposed to be a low level v3 LDAP namespace so assumed it wouldn't be polluted with AD specific types. The following code is from a monitor background worker that was already using the System.Directory.Protocols namespace. It opens an async long running request to AD and listens for changes using the Control DirSyncRequestControl.
SearchRequest request = new SearchRequest(
mDNSearchRoot,
mLdapFilter,
SearchScope.Subtree,
mAttrsToWatch
);
request.Controls.Add(
new DirSyncRequestControl(
mCookie,
mDirSyncOptions
)
);
mConn.BeginSendRequest(
request,
mRequestTimeout,
PartialResultProcessing.NoPartialResultSupport,
endPollDirectory,
null
);
It sends a cookie as a byte[] that tells the directory when to start querying from which is handy in case the background worker crashes and needs a restart later. In the endPollDirectory callback an update cookie is received and persisted immediately to the filesystem in the event of a restart being needed we always know when we last received results from. That cookie is loaded on restart and passed back with the DirSyncRequestControl.
The issue I'm facing is that DirSyncRequestControl is operating against an OID which specifically is an Active Directory extension, not standard LDAP. Our corporate directory is on IBM based LDAP and can't have AD OIDs and Controls applied. Standard LDAP supports "Persistent Search" 2.16.840.1.113730.3.4.3 but .NET doesn't provide a Control that could be added as in the above code. There's also no way to pass arguments like a cookie. The idea with the Persistent Search control is that you open the connection and as time passes the LDAP server sends changes back which I could response to. But on initiating the connection there's no way to specify when to returns results from, only results since the request was started will be received. If the monitor were to die and a directory change happened before the monitor could restart those changes could be neve be handled.
Does anyone know if there's an existing Control compliant with standard LDAP that could be added to the request which operates the way the AD specific DirSyncRequestControl does where a start date time could be passed?
Does anyone know if there's an existing Control compliant with standard LDAP that could be added to the request which operates the way the AD specific DirSyncRequestControl does where a start date time could be passed?
Standard would be the 1.3.6.1.4.1.4203.1.9.1.1 "Sync Request" control from RFC 4533, which is the basis of "Syncrepl" directory replication in OpenLDAP and 389-ds.
(Though "standard" does not guarantee that IBM's LDAP server will support it – or that it's enabled on your server specifically, similar to how OpenLDAP requires loading the "syncprov" overlay first.)
2.2. Sync Request Control
The Sync Request Control is an LDAP Control [RFC4511] where the
controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.1 and the
controlValue, an OCTET STRING, contains a BER-encoded
syncRequestValue. The criticality field is either TRUE or FALSE.
syncRequestValue ::= SEQUENCE {
mode ENUMERATED {
-- 0 unused
refreshOnly (1),
-- 2 reserved
refreshAndPersist (3)
},
cookie syncCookie OPTIONAL,
reloadHint BOOLEAN DEFAULT FALSE
}
The Sync Request Control is only applicable to the SearchRequest
Message.
Although dotnet doesn't support this control natively (it seems to focus on just supporting Active Directory extensions), it should be possible to create a custom class similar to the Dir­Sync­Request­Control class with the correct OID and correct BER serialization (and somehow handle the "Sync Done" control that delivers the final sync cookie to you, etc).
OpenLDAP's ldapsearch supports calling this control via ldapsearch -E sync=rp[/cookie]. On the server side, slapd supports this control for databases that have the "syncprov" overlay loaded (which is required for replication).
389-ds (Red Hat Directory Server) supports this control if the plug-in is enabled.
The other approach is to have a persistent search for (modifyTimestamp>=...) and keep track of the last received entry change timestamp in place of the "cookie". This isn't very accurate, unfortunately.

Unable to make bot reply in thread on Slack

I have a single-tenant bot, built on Bot.Builder 18.1 that is currently running in a Slack channel. My challenge is that I would like the bot to always reply in a thread, when possible, so:
If already in a thread, reply in that thread
If on a channel, create a new thread and reply there
As far as I understand, the way to achieve this is to set the property thread_ts to the value of the ts property. I can get this value, however all attempts to set thread_ts still only give me replies in the channel directly, and not in a new thread, as expected. My last failed attempt was setting it on the reply message:
string? thread_ts = null;
if (slackChannelData is not null)
{
thread_ts = slackChannelData?.SlackMessage?._event?.ts;
}
reply.Conversation.Properties[nameof(thread_ts)] = thread_ts;
And yes, I do get the ts value out of that :)
I also attempted to use the Slack Adapter, however it fails for som authentication reasons, even though I've set it's required configuration values (SlackBotToken, SlackVerificationToken and SlackClientSigningSecret). I cannot get the Slack Adapter to get past the authentication. The slack adapter follows the latest example on GitHub, and targets the community.adapters.slack version 4.13.5
So my question is:
Does anyone know if it is possible to use the Bot Framework and a slack channel to reply in thread in Slack given my want above?

ProcessReceivedMessage Error in MqttDotNet

I am building a .NET IoT project that requires MQTT for communication. For the broker I use GnatMQ and for clients I use MqttDotNet (for mobile compatibility). The client library builds, connects, and sends messages fine but I get an error whenever the client’s PublishArrivedDelegate is triggered (i.e. message received event).
The error occurs on retained messages as well as standard received messages. The MqttDotNet error log is here.
Console output:
It seems the error is captured in the QoSManager.cs on line 91:
else if (mess.QualityOfService == QoS.OnceAndOnceOnly)
{
_responses.Add(mess.MessageID, new MqttPubrelMessage(mess.MessageID));
}
NOTE: I am using the raw libraries (as they are) without added code.
Has anyone tried these libraries and can maybe confirm that it worked for them without issues? Until then, I guess it's debugging till the extreme.
Update 1: The error only persists on subscribe with QoS level 2.
Update 2: The error can be prevented by adding a handle to prevent duplicates from being added to the hashtable, as pointed out by #hardillb . But this does not SOLVE the actual issue here.
The issue still persists on publish and subscribe with QOS 2. The problem is that the onClientPublishedArrived is being triggered exactly 3 times whenever a message gets received and exactly 2 times when a message get received as retained. NOTE that when I test this with HiveMQ the issue is gone. The problem only persists when using the GnatMQ broker.
Looks like you are trying to add duplicate keys to a Hashtable, this will be being caused by mess.MessageID returning the same value for multiple messages.
The C# implementation looks like it throws an exception rather replacing the original value with the new value.
If you just need a unique key for the Hashtable you could use something like the timestamp

Converting Microsoft EWS StreamingNotification Example to a service

I've been working to try and convert Microsoft's EWS Streaming Notification Example to a service
( MS source http://www.microsoft.com/en-us/download/details.aspx?id=27154).
I tested it as a console app. I then used a generic service template and got it to the point it would compile, install, and start. It stops after about 10 seconds with the ubiquitous "the service on local computer started and then stopped."
So I went back in and upgraded to C# 2013 express and used NLog to put a bunch of log trace commands to so I could see where it was when it exited.
The last place I can find it is in the example code, SynchronizationChanges function,
public static void SynchronizeChanges(FolderId folderId)
{
logger.Trace("Entering SynchronizeChanges");
bool moreChangesAvailable;
do
{
logger.Trace("Synchronizing changes...");
//Console.WriteLine("Synchronizing changes...");
// Get all changes since the last call. The synchronization cookie is stored in the
// _SynchronizationState field.
// Only the the ids are requested. Additional properties should be fetched via GetItem
//calls.
logger.Trace("Getting changes into var changes.");
var changes = _ExchangeService.SyncFolderItems(folderId, PropertySet.IdOnly, null, 512,
SyncFolderItemsScope.NormalItems,
_SynchronizationState);
// Update the synchronization cookie
logger.Trace("Updating _SynchronizationState");
the log file shows the trace message ""Getting changes into var changes." but not the "Updating _SynchronizationState" message.
so it never gets past var changes = _ExchangeService.SyncFolderItems
I cannot for the life figure out why its just exiting. There are many examples of EWS streaming notifications. I have 3 that compile and run just fine but nobody as far as I can tell has posted an example of it done as a service.
If you don't see the "Updating..." message it's likely the sync threw an exception. Wrap it in a try/catch.
OK, so now that I see the error, this looks like your garden-variety permissions problem. When you ran this as a console app, you likely presented the default credentials to Exchange, which were for your login ID. For a Windows service, if you're running the service with one of the built-in accounts (e.g. Local System), your default credentials will not have access to Exchange.
To rectify, either (1) run the service under the account you did the console app with, or (2) add those credentials to the Exchange Service object.

Push Notifications with PushSharp - the basics

I need to push notifications to tens of thousands of iOS devices that my app installed. I'm trying to do it with PushSharp, but I'm missing some fundamental concepts here. At first I tried to actually run this in a Windows service, but couldn't get it work - getting null reference errors coming from _push.QueueNotification() call. Then I did exactly what the documented sample code did and it worked:
PushService _push = new PushService();
_push.Events.OnNotificationSendFailure += new ChannelEvents.NotificationSendFailureDelegate(Events_OnNotificationSendFailure);
_push.Events.OnNotificationSent += new ChannelEvents.NotificationSentDelegate(Events_OnNotificationSent);
var cert = File.ReadAllBytes(HttpContext.Current.Server.MapPath("..pathtokeyfile.p12"));
_push.StartApplePushService(new ApplePushChannelSettings(false, cert, "certpwd"));
AppleNotification notification = NotificationFactory.Apple()
.ForDeviceToken(deviceToken)
.WithAlert(message)
.WithSound("default")
.WithBadge(badge);
_push.QueueNotification(notification);
_push.StopAllServices(true);
Issue #1:
This works perfectly and I see the notification pop up on the iPhone. However, since it's called a Push Service, I assumed it would behave like a service - meaning, I instantiate it and call _push.StartApplePushService() within a Windows service perhaps. And I thought to actually queue up my notifications, I could do this on the front-end (admin app, let's say):
PushService push = new PushService();
AppleNotification notification = NotificationFactory.Apple()
.ForDeviceToken(deviceToken)
.WithAlert(message)
.WithSound("default")
.WithBadge(badge);
push.QueueNotification(notification);
Obviously (and like I already said), it didn't work - the last line kept throwing a null reference exception.
I'm having trouble finding any other kind of documentation that would show how to set this up in a service/client manner (and not just call everything at once). Is it possible or am I missing the point of how PushSharp should be utilized?
Issue #2:
Also, I can't seem to find a way to target many device tokens at once, without looping through them and queuing up notifications one at a time. Is that the only way or am I missing something here as well?
Thanks in advance.
#baramuse explained it all, if you wish to see a service "processor" you can browse through my solution on https://github.com/vmandic/DevUG-PushSharp where I've implemented the workflow you seek for, i.e. a win service, win processor or even a web api ad hoc processor using the same core processor.
From what I've read and how I'm using it, the 'Service' keyword may have mislead you...
It is a service in a way that you configure it once and start it.
From this point, it will wait for you to push new notifications inside its queue system and it will raise events as soon as something happens (delivery report, delivery error...). It is asynchronous and you can push (=queue) 10000 notifications and wait for the results to come back later using the event handlers.
But still it's a regular object instance you will have to create and access as a regular one. It doesn't expose any "outside listener" (http/tcp/ipc connection for example), you will have to build that.
In my project I created a small selfhosted webservice (relying on ServiceStack) that takes care about the configuration and instance lifetime while only exposing the SendNotification function.
And about the Issue #2, there indeed isn't any "batch queue" but as the queue function returns straight away (enqueue and push later) it's just a matter of a looping into your device tokens list...
public void QueueNotification(Notification notification)
{
if (this.cancelTokenSource.IsCancellationRequested)
{
Events.RaiseChannelException(new ObjectDisposedException("Service", "Service has already been signaled to stop"), this.Platform, notification);
return;
}
notification.EnqueuedTimestamp = DateTime.UtcNow;
queuedNotifications.Enqueue(notification);
}

Categories