Return initial data on subscribe event in django graphene subscriptions - websocket

I'm trying to response to user on subscribe. By example, in a chatroom when an user connect to subscription, the subscription responses him with data (like a welcome message), but only to same user who just connect (no broadcast).
How can I do that? :(
Update: We resolve to use channels. DjangoChannelsGraphqlWs does not allow direct back messages.

Take a look at this DjangoChannelsGraphQL example. Link points to the part which is there to avoid "user self-notifications" (avoid user being notified about his own actions). You can use the same trick to send notification only to the user who made the action, e.g. who just subscribed.
Modified publish handler could look like the following:
def publish(self, info, chatroom=None):
new_msg_chatroom = self["chatroom"]
new_msg_text = self["text"]
new_msg_sender = self["sender"]
new_msg_is_greetings = self["is_greetings"]
# Send greetings message only to the user who caused it.
if new_msg_is_greetings:
if (
not info.context.user.is_authenticated
or new_msg_sender != info.context.user.username
):
return OnNewChatMessage.SKIP
return OnNewChatMessage(
chatroom=chatroom, text=new_msg_text, sender=new_msg_sender
)
I did not test the code above, so there could be issues, but I think it illustrates the idea quite well.

Related

Perform action on seen/unseen messages with socket.io

What is the best practice to handle seen/unseen messages in a chat room application based on Nodejs/SocketIO/React.
Consider User1 sends a message to a room. If another user has seen that message, notify all users that the state of message has been seen.
In my opinion using message brokers can be the better solution instead socket. I actually think that socket should only handle chat messages that are synchronously. but for seen/unseen status I prefer message brokers that are asynchronous. Are there any solutions or best practice in large scale applications?
It's unclear what you have currently tried, meaning that I can only advise solutions in order to achieve your aim.
To firstly identify that a message was seen, IntersectionObserver is an inbuilt API that detects when an element has entered the viewport, meaning that it is visible, therefore; obviously seen. I have added comments in the code below where you should add a function to call to the server that the message was seen, however, that's up to you to implement.
const observer = new window.IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
// Send a message to the server that the user has viewed the message.
// Eg. socket.emit('read-message', message.id)
return
}
}, {
root: null,
threshold: 0.1,
})
observer.observe(document.getElementById(message.id));
Additionally, there's no need to use message broker, as socket.io can handle simple interactions such as this.
You then need to send a message to the server that denotes the specified message ID was seen, then broadcast to every other client that the state was changed, and update it to read - if that's needed.

Responding to Conversations async: Graph or Bot?

I have a Teams Message extension that returns a Task response which is a medium sized embedded web view iFrame
This is working successfully; including added a custom Tab within the channel and other nice magic calls to Microsoft Graph.
What I am confused about is how to do (and this is probably my not understanding the naming of things)
insert "something" Back into the Message/Post stream which is a link to newly created Tab ... like the what you get when you have a "configureTabs" style Tab created -- there is a friendly Message (Post) in the chat pointing to this new Tab.
do I do this with Microsoft Graph or back through the Bot?
the code that does the communication may be a different service elsewhere that is acting async ... so it needs to communicate with something somewhere with context. Confused if this is the Bot with some params or Microsoft Graph with params.
how to insert an image (rather than a link to the tab) into the Message/Post stream -- but showing the image not a link off to some random URL (ie: )
could not find any samples that do this; again, will be async as per above; but the format of the message will be a Card or something custom?
So just to be clear, a Task Response is NOT the same as a Tab, albeit that they might end up hosted in the same backend web application (and also albeit that your TAB can actual bring up your Task Response popup/iframe using the Teams javascript library).
Aside from that, in order to post something back to the channel, like when the Tab is created, there are two ways to do so:
First is to use Graph Api's Create ChatMessage option (this link is just for a channel though - not sure if your tab/task apply to group chats and/or 1-1 chats as well).
2nd Option is to have a Bot be part of your application as well. Then, when you're ready to send something to the channel, you'd effectively be sending something called a "pro-active messaging". You need to have certain reference data to do this, which you would get when the bot is installed into the channel ("conversation reference", "ServiceUrl", and so on). I describe this more in my answer at Programmatically sending a message to a bot in Microsoft Teams
With regards sending the image, either of the above would work here too, in terms of how to send the image. As to the sending of an image, you'd need to make use of one of the kinds of "Cards" (basically "richer" messages than just raw text). You can learn more about this at Introducing cards and about the types of cards for Teams at Card reference. There are a few that can be used to send an image, depending on perhaps what else you want the card to do. For instance, an Adaptive Card can send an image, some text, and an action button of some sort.
Hope that helps
To close the loop for future readers.
I used the following Microsoft Graph API docs, and the posting above, and this is working: Create chatMessage in a channel and Creating a Custom Microsoft Graph call from the SDK
The custom graph call (as it is not implemented in the .NET SDK at the time of this response) looks something like:
var convoReq = $"https://graph.microsoft.com/beta/teams/{groupId}/channels/{channelId}/messages";
var body = this.TeamsMessageFactory(newCreatedTabUrl, anotherstring).ToJson();
var postMessage = new HttpRequestMessage(HttpMethod.Post, convoReq)
{
Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json")
};
await _graphClient.CurrentGraphClient.AuthenticationProvider.AuthenticateRequestAsync(postMessage);
var response = await _graphClient.CurrentGraphClient.HttpProvider.SendAsync(postMessage);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return true;
}
The groupId and channelId are found elsewhere; and the TeamsMessageFactory is just some boilerplate that serialized the C# object graph for the POST request, as detailed in Create chatMessage in a channel

How Can I Use xmpp4r To Detect The Online/Offline Status Of A Given Jabber ID?

What is the proper xmpp4r way to know if a given contact is online before sending them a message?
Can you post sample xmpp4r code for doing this?
Here is my use case:
If contact online, send :normal message
Else, email contact
Here are things I have working code for:
Send messages of various types
Get a roster/contact list
Register a call back to detect changes in presence
However, I can't find a place that directly addresses a work flow like this:
Loop through each JID in your roster
If jid.is_online? == true, send IM
Else, send email
I've read that you should send a JID a message of type :headline and if that fails, you know the user is offline. In my tests, if the user is ONLINE, they'll receive a message of type headline. This is suboptimal, as users should only receive messages to read, not noise to determine online status.
I've read that on sign on, all of your contacts will bounce a presence status back at you, and that status is the sole indication that they are online - assuming that there isn't a disconnect or presence change you've yet to receive. So you should register a presence call back, record the initial users who ping you back, and then add or remove from the list based on your running roster presence callback.
If this is truly the way to do it:
Can I get some example code of how to collect all the "I'm here" presence confirmations on sign on via xmpp4r?
Why, oh why, was xmpp designed this way and why is this better than offering an "is_online_and_available" method?
So the answer here is adding a message call back and checking inside the block for the type:
m = Message.new(to, body)
cl.send(m)
cl.add_message_callback do |m|
if m.type == :error
puts "type: #{m.type}"
else
puts "not an error"
end
end
This requires threading as you have to be listening for the response.

Pusher App Client Events

I'm writing a multiplayer chess game, and using Pusher for the websocket server part.
Anyways, if I have a list of users, and I select any one of them and challenge them, how do I send challenge to just that one user? I know I would use the client event like:
channel.trigger("client-challenge_member1", {some : "data"});
But this event would have to have already been created I think. So do I create this event dynamically after each member subscribes? as possibly in:
channel.bind("pusher:subscribed_completed", function(member) // not sure of correct syntax but...
{
channel.bind("client-challenge_" + member.memberID, function(data)
{
alert(data.Name + " is challenging you.");
});
});
I would think there'd be a overloaded method for trigger, like:
channel.trigger(eventName, data, memberID)
But I cannot see anything like this. Any ideas? Thanks.
I ran into this problem on my application. At this time Pusher does not provide methods for sending events to a specific user. I think the approach that you mentioned would work for your situation. For my application I had each user subscribe to a channel with their user id as the channel id, then I could send messages to a single user through that channel.
client = new Pusher(PUSHER_API_KEY);
channel = client.subscribe(user_id);
channel.bind('my_event',function(data){
//Do stuff
});
I talked this approach over with the pusher team and they assured me there was no real overhead in having the extra channels. The new Pusher() command is the code that creates a new socket connection so you don't have to worry about extra sockets per channel or anything like that. Hope this helps.
I'm from Pusher. As Braden says, you can easily make a channel per user. This is more efficient than having the user id in the event name which means you spam everyone with useless messages.
This is an area we want to improve on further, so thanks for the feedback.
If you're able to consider another service, Beaconpush has the ability to send messages to a specific user.
From their site:
POST /1.0.0/[API key]/users/[user]

Using the xmpp4r Ruby gem, how can I synchronously discover if a contact is online?

I'm new to XMPP and the xmpp4r library, so please forgive my noob question if this is obviously documented somewhere.
What's the most straightforward way, in a synchronous manner, to find out if a given JID is online? (so that I can call something like is_online?(jid) in an if statement)
My details:
I'm writing a Sinatra app that will attempt to send a message to a user when a particular url gets requested on the web server, but it should only try to send the message to the user if that user is currently online. Figuring out if a given JID is online is my problem.
Now, I know that if I connect and wait a few seconds for all the initial presence probe responses to come back to the Roster helper, then I can inspect any of those presences from my Roster and call #online? on them to get the correct value. But, I don't know when all of the presence updates have been sent, so there's a race condition there and sometimes calling #online? on a presence from my roster will return false if I just haven't received that presence probe response yet.
So, my current thinking is that the most straightforward way to find out if someone is online is to construct a new Presence message of type :probe and send that out to the JID that I'm interested in. Here's how I'm doing it right now:
#jabber is the result of Client::new
#email is the jid I'm interested in polling
def is_online?(jabber, email)
online = false
p = Presence.new
p.set_to(email)
p.set_from(jabber.jid)
p.set_type(:probe)
pres = jabber.send(p) do |returned_presence|
online = returned_presence.nil?
end
return online
end
Now, this works in cases where the user is actually online, but when the user is offline, it looks like the presence probe message that comes back is being caught by some other presence_callback handler that doesn't know what to do with it, and my is_online? function never finishes returning a value.
Can anyone help me by providing a simple example is_online? function that I can call, or point me in the right direction for how I can detect when the roster is done getting all the initial presence updates before I try checking a presence for #online?
As it turns out, there's not a synchronous way to ask for a JID presence. You've just got to ask for what you want, then wait for your response handler to fire when the response arrives.

Resources