#Send daily reminder via dm

1 messages · Page 1 of 1 (latest)

pale python
#

I would like to offer my users a reminder function. The users register for this function via slashcommand, and the user's Discord ID, among other things, is then entered in the database. A reminder is sent to these users via DM once a day at a certain time. And at this point I have a problem.
With

SocketUser user = _client.GetUser(subscriber.discord_id);

Unfortunately I get a null value for the SocketUser.
If I understood correctly, this is because the user is not in the cache, which is why I

_client.Rest.GetUserAsync(subscriber.discord_id

can use. Here I actually get a RestUser object with the correct data for the associated DC ID. However, then i get here

var dmChannel = await subscriber.CreateDMChannelAsync();

the error

System.NullReferenceException: 'Object reference not set to an instance of an object.'

Unfortunately I just don't understand why. Is it not possible to send private messages using a DC ID if the user has not previously interacted with the bot on the DC server? Since I'm currently testing the function on my DC ID and am on the same DC server as the bot, I'm ruling out the problem

ruby rampart
#

System.NullReferenceException:
what is the stacktrace?

wicked igloo
#

Since I'm currently testing the function on my DC ID and am on the same DC server as the bot

Might want to;

SocketGuild guild; //Grab a ref to the server
await guild.DownloadUsersAsync();

or

await _client.DownloadUsersAsync([guild]);

Instead of attempting to get individual users async, depending on server size.

At the very worst wrap:

_client.Rest.GetUserAsync(subscriber.discord_id

In a try/catch, and add a null/type check before you use the resultant object.

ruby rampart
#

await guild.DownloadUsersAsync();
instead of doing this you could just set AlwaysDownloadUsers = true in hte socket config

pale python
#

Thanks for the super quick answers

pale python
# wicked igloo > Since I'm currently testing the function on my DC ID and am on the same DC ser...

Why do you download all users? Isn't that a bad thing for a large DC server? I don't want to send a DM to every user per se, but only those who also want a reminder. The DC IDs are then in the database. Unfortunately I can't send private DMs from it. For the SocketUser I get zero, for the RestUser I actually get a user, but then it crashes with the

var dmChannel = await subscriber.CreateDMChannelAsync();
wicked igloo
# pale python Why do you download all users? Isn't that a bad thing for a large DC server? I d...

Caching purposes, especially since if this is running once a day, you're performing a single load of all users before sending the dms.

All the instances where my codebase is using CreateDMChannelAsync(), it's being targetted on some variation of SocketUser, be that SocketGlobalUser, or otherwise.

That's not to say you can't create a DM channel off of a RestUser, as I'm genuinely not sure - but the SocketUser is a more focused type for the context of sending messages from within a guild, so if you're getting null there, that's probably a more indicative problem.

How are you attempting to fetch the user as Socket versus Rest?

#
public static async Task<DMResult> BoolSendDm(IUser dmUser, string message) {
    if(dmUser is null || dmUser?.Id is null) return DMResult.CannotSendToUser;
    var result = DMResult.Success;
    try {
        var dmChannel = await dmUser.CreateDMChannelAsync();
        if(dmChannel is null) return DMResult.DiscordError;
        await dmChannel.SendMessageAsync(message);
    } catch(HttpException ex) {
        result = ex.DiscordCode == DiscordErrorCode.CannotSendMessageToUser ? DMResult.CannotSendToUser : DMResult.DiscordError;
    } catch (Exception) {
        return DMResult.CannotSendToUser;
    }
    return result;
}

In the context of the app, it's providing an IUser to this method, however in all cases where it's being used, there are SocketUser, SocketGuildUser, or the raw IUser from:

_client.GetUserAsync(258383847148879874);

As the IUser rather than the RestUser.

#

Do some try/catch and some logging of types to see what things are coming back as, and better exception logging - the stacktrace you posted is ok, but there's very little info besides line number about what's going wrong.

pale python
#

I'm still relatively new to this, but thank you for your patience and tips.

Regarding your question, how do I call SocketUser, this would be the corresponding part of the code:

wicked igloo
#

nodders how you have it there is correct

pale python
#

That's nice to know, even if it doesn't explain why I get null for my SocketUser despite the correct DC ID 😄

wicked igloo
#

I would caution around using _client.GetUser() inline though, since that's a synchronous call with a timeout.

ruby rampart
#

no

#

GetUser is synchronous, yes
but it doesn't make any api calls

#

it only looks the user up in the cache

wicked igloo
#
await SendVoteRemidnerDC(_client.GetUser(subscriber.discord_id));

var socketUser = await _client.GetUserAsync(subscriber.discord_id);
SendVoteRemidnerDC(socketUser);

If the user isn't cached, they won't be returned.

pale python
#

Ok, then I understood correctly why I got null for the SocketUser.

If I now use GetUserAsync, it will get the user I want and then I should be able to send the user a DM?

wicked igloo
#

Theoretically yes