ServiceStack event for client disconnect - c#

I'm experimenting with ServiceStack's Server Events feature and want to make a sort of "online users" test app. The idea is I want to update each user that connects to a channel "Users" whenever a new user joins or leaves. The problem is I cannot find a way to detect when a subscription/user leaves/disconnects.

The ServerEventsClient.OnCommand callback is fired when a User Joins, Leaves or Updates their ServerEvent subscription.
You can also fetch a list of all active subscribers from a channel at anytime with:
var sseClient = new ServerEventsClient(...);
var response = sseClient.ServiceClient.Get(new GetEventSubscribers {
Channels = sseClient.Channels
});
Which will return a List of untyped Dictionary<string,string> containing the subscribers public info.
I've also just added a Typed API for GetChannelSubscribers() in this commit that's now available from v4.0.57 on MyGet which provides a Typed API to fetch all users subscribed to the ServerEventsClient channels, e.g:
var channelSubscribers = sseClient.GetChannelSubscribers();

Related

Where to receive watch notifications for gmail in .NET?

I'm trying to receive watch notification for Gmail mailboxes in my .NET C# program.
I have the following code:
WatchRequest body = new WatchRequest()
{
LabelIds = labelIds,
TopicName = PrivateKeys.GoogleGmailTopic
};
WatchResponse response = new UsersResource.WatchRequest(_gmailService, body, "me")
{
Key = PrivateKeys.GoogleApiKey,
OauthToken = AccessToken
}
.Execute();
... and it seems to work, since I get a response.
But where do I receive these notifications inside my program? How can I configure the event entry point?
Assuming you did the preliminary work to set up a Cloud Pub/Sub client (described here: https://developers.google.com/gmail/api/guides/push#initial_cloud_pubsub_setup), you should have a Pub/Sub subscription - either PULL or PUSH.
In order to get the notifications, your application should initiate a subscriber, you can follow the instructions in https://cloud.google.com/pubsub/docs/pull for PULL or in https://cloud.google.com/pubsub/docs/push for PUSH. Configuring the event entry point should be done as part of the subscriber set up.

Manage a long-running operation in MS Teams Bot

I am using the following sample / article to Manage a Long-running operation in MS Teams Bot.
https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-howto-long-operations-guidance?view=azure-bot-service-4.0
In step 5, a DirectLineClient is being created and an Event Activity is sent to Bot using PostActivityAsync.
var responseActivity = new Activity("event");
responseActivity.Value = originalActivity;
responseActivity.Name = "LongOperationResponse";
responseActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
var directLineSecret = Environment.GetEnvironmentVariable("DirectLineSecret");
using(DirectLineClient client = new DirectLineClient(directLineSecret))
{
var conversation = await client.Conversations.StartConversationAsync();
await client.Conversations.PostActivityAsync(conversation.ConversationId, responseActivity);
}
However, I need the above sample to work for MS Teams Bot and not the DirectLineClient.
I used Microsoft.Bot.Connector.ConnectorClient but StartconversationAsync and PostActivityAsync methods are not available.
I tried the methods available in Microsoft.Bot.Connector.ConnectorClient
connectorClient.Conversations.CreateConversationAsync(conversationparameters)
connectorClient.ConversationsCreateDirectConversationAsync(botAccount, userAccount, (Activity)newActivity);
connectorClient.Conversations.SendToConversationAsync(conversationid, (Activity)newActivity);
But all the methods failed with Bad Requestwith the error as seen in the Response:
{"error":{"code":"BadArgument","message":"Unknown activity type"}}
The newActivity is created as below:
var messagnewActivity = new Activity("event");
newActivity.Value = originalActivity;
newActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
newActivity.Type = "event";
newActivity.Conversation = new ConversationAccount { Id = originalActivity.Conversation.Id };
newActivity.ChannelId = originalActivity.ChannelId;
Can someone please suggest how do I pass the Activity (Event Activity type) to MS Teams Bot.
Thanks
Gagan
I'm not really familiar with Direct Line, but I think it's effectively an -alternative- type of bot to Teams, so if you're trying to do this inside Teams, it explains the issue. In principle, the basic idea is quite simple though:
you store state somehow (e.g. in memory or in a database) to indicate that the long running operation is in progress for the user
when the long-running process is complete, your code (which could live OUTSIDE your bot, e.g. in an Azure Function) can send the user a message AS IF IT WAS the bot - this is called Pro-Active Messaging and you can read more about it at https://learn.microsoft.com/en-us/graph/teams-proactive-messaging.
This is to inform you that I was facing the same issue sometime before then I found a tweak in the code while debugging. when it calls twice recursively then the Activity Id is the same as the previous one. you can check if the activity id is the same then return the request else go with it.

Registering displayName with ServiceStack's ServerEventsClient before invoking Start

I am developing a small chat implementation in my app and I want to be notified when someone has joined/left the channel and who that person is.
On the client side I am listening to OnJoin and OnLeave, which take a ServerEventCommand object, in order to showcase the message, but the ServerEventCommand object is populated with some seemingly random properties on the server side after I have registered on the client side.
I'm looking into the ServerEventsClient object and all of its properties but cannot find a way for me to set the properties I want before invoking Start().
The displayName isn't a property you set, it's sent by the server to identify which users are joining/leaving the channels you're subscribed to. It will either contain the UserName of the User or if your Auth Provider doesn't use UserNames (e.g. Uses Email or id number instead) it will use the DisplayName property of the Users Session.
You need to register event handlers in your Server Events Client before calling .start(), e.g using the TypeScript ServerEventsClient:
const channels = ["home"];
const client = new ServerEventsClient("/", channels, {
handlers: {
onConnect: (sub:ServerEventConnect) => { // Successful SSE connection
console.log("You've connected! welcome " + sub.displayName);
},
onJoin: (msg:ServerEventJoin) => { // User has joined subscribed channel
console.log("Welcome, " + msg.displayName);
},
onLeave: (msg:ServerEventLeave) => { // User has left subscribed channel
console.log(msg.displayName + " has left the building");
},
}).start();
Only after you've started your subscription and are subscribed to your channel will you receive any events.
Channel Subscribers
Most Server Event Clients also allow you fetch a list of Users, e.g. with the TypeScript client you can call getChannelSubscribers():
client.getChannelSubscribers()
.then(users => users.forEach(x =>
console.log(`#${x.userId} #${x.displayName} ${x.profileUrl} ${x.channels}`)));
Alternatively you can call /event-subscribers directly to fetch the list of users in each channel, e.g:
$.getJSON("/event-subscribers?channels={{ channels }}", function (users) {
});
Example Chat Apps
For reference there are a number of simple Apps written in different languages which uses the different Server Event Clients available to create a simple Chat App:
JavaScript Client
Chat https://github.com/NetCoreApps/Chat
React Chat https://github.com/ServiceStackApps/ReactChat
TypeScript Client
Web, Node.js and React Native Chat https://github.com/ServiceStackApps/typescript-server-events
C# Server Events Client
Xamarin.Android Chat https://github.com/ServiceStackApps/AndroidXamarinChat
Java Client
Android Java Chat https://github.com/ServiceStackApps/AndroidJavaChat

How to retrieve a list of discord users in a channel

I'm trying to write something in C#, a simple console app that will connect to Discord, retrieve a list of all users in a channel (all currently online would suffice, but everyone who has channel access would be even better.) The app does not need to maintain a connection, just jump in, grab the list of user names and jump out.
I've experimented with DiscordSharp, but it doesn't seem to quite be working out. I think I am getting a client connection but I can't seem to find any channels via GetChannelByName or GetChannelByID. I am not set on using DiscordSharp as the only solution, though I do like the library so far.
A "server" in discord is called a Guild. Per the documentation a Guild can have a list of Channel objects. In the Channel object there is a property called recipients which should give you all users of that channel.
I wouldn't recommend using DiscordSharp because according to their GitHub it is a dead project. They recommend using DSharpPlus or Discord.NET.
I just checked the documentation for Discord.NET and found a few methods you could use:
GetGuildAsync(UInt64, RequestOptions): This will get you the RestGuild (server) based on the server ID.
GetChannelAsync(UInt64, RequestOptions): This will get you the RestChannel based on the channel ID.
Using either one of these will eventually get you a RestChannel object that will contain a GetUsersAsync(CacheMode, RequestOptions) method that will allow you to get the collection of IUSer
In a command module you can do this:
public class AllUsers : ModuleBase<SocketCommandContext>
{
public async Task Traitement()
{
var users = Context.Guild.Users;
//you can loop here on users and do the traitement
}
}

Can we filter messages from Amazon SQS queue by message attributes?

For now I have tried to filter the messages based on Message Attribute Name="Class". As you can see in the below code
//Specify attribute list
List<string> AttributesList = new List<string>();
AttributesList.Add("Class");
receiveMessageRequest.MessageAttributeNames = AttributesList;
receiveMessageRequest.QueueUrl = urlSQS;
receiveMessageRequest.MaxNumberOfMessages = 10;
ReceiveMessageResponse receiveMessageResponse = objClient.ReceiveMessage(receiveMessageRequest);
But the messages are not been filtered based on the provided MessageAttributeName = "class".
receiveMessageRequest.MessageAttributeNames = AttributesList;
This tells SQS which message attributes you want it to return with the message if the are present on the message. It is not a message filter. If the attributes aren't present, nothing happens.
But your confusion seems understandable -- it's not actually obvious why the API even has this functionality, though it may be a holdover from when SQS supported only smaller messages than it does today, or it may be so that you can avoid spending any time parsing information from the response that you will end up discarding. I almost always just ask for All.
Please note this regarding messaging services on AWS
SQS : No filtering support ( while picking up messages)
SNS : Supports attributes-based filtering: subscriber can set a subscription attribute (a subscription filter policy) which is applied on incoming messages and only relevant messages can be sent to the subscriber.
EventBridge: Amazon EventBridge supports declarative filtering using event patterns. With event pattern content filtering you can write complex rules that only trigger under very specific conditions. For instance, you might want a rule that will trigger only when a field of the event is within a specific numeric range, if the event comes from a specific IP address, or only if a specific field does not exist in the event JSON.
Please refer my article for a detailed difference between main messaging frameworks on AWS.
https://www.linkedin.com/pulse/mastering-art-decoupling-application-architecture-aws-amit-meena/
It depends on how the message in question gets onto the queue. If you are pushing the message via SNS then yes you can filtered messages; https://docs.aws.amazon.com/sns/latest/dg/message-filtering.html
Any other filtering mechanism doesn't exist right now.
Hope that helps!
As per the AWS SDK method, we can use following code to do the filter.
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest("QUEUE URL" );
receiveMessageRequest.setMaxNumberOfMessages(Integer.valueOf(1));
private static AmazonSQS sqs;
List<Message> messages = sqs.receiveMessage(receiveMessageRequest.withMessageAttributeNames("Attribute Name")).getMessages();
If you want all the message then use given code
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest("QUEUE URL" );
receiveMessageRequest.setMaxNumberOfMessages(Integer.valueOf(1));
private static AmazonSQS sqs;
List<Message> messages = sqs.receiveMessage(receiveMessageRequest.withMessageAttributeNames("All")).getMessages();

Categories

Resources