Spring STOMP - immediate response - spring

I am implementing an Angular client that connects to a spring boot backend via STOMP.
When a client connects and wants to create a "business-group", said group is created in the backend and gets a UUID; and from that moment on other clients should be able to send to and receive messages from that group.
So I am creating a topic with said business-group id in the destination - something like
#MessageMapping("/foo/group/{id}")
However I want the creator of the group to immediately receive the business group id to be able to subscribe to it himself as well. And to be able to share the id with others (user to user).
I have used raw sockets for this before, so I was able to just use the connected user's session and then send back the id to him after the had sent the create-message. But since the session handling was business-group-ID based (so that only the users in a specific group receive the messages from that group), the whole dividing user sessions by business-group-ID had to be done manually and I was looking to upgrade this to something that does that handling for me.
However I am not sure how to achieve this with spring stomp. So my question is, is there a way for the creator of such a group to immediately receive the id as an answer/response to his initial "request"?
Because he can't subscribe to anything before he receives the group id.
Background:
It's basically like a chat app where a user can create a group/chatroom and then share it with others (via URL - which contains the ID); everyone that subscribes to it can then receive msgs from it and send msgs into it. But to do so the creator first needs the created ID.

I found a solution. This can be done via #SendToUser
#MessageMapping("/group.create")
#SendToUser(value="/topic/group.create", broadcast=false)
public Response createGroup(#Payload Message message) {
...
return createResponseWithId();
}
On the other end you only need to subscribe to '/user/topic/group.create'.

Related

Slack Bot send DM message to the User

I want to send message as DM to the users, so I've come with some questions;
1- There are two ways to send DM to the user;
the first one open a conversation with user by using conversation.open, and send message. Then if I want to send the message to the same user, I use conversation.list and find the conversationId by userId, then send message to the same channel again.
Second one is just basically using userId as channelId parameter in chatPostMessageRequest.
I've tried both ways, and both of them are sending message as DM. So, what is the purpose of using conversation.open? I'm asking this because nearly all the answers say you should do this etc.
2- Seems like there is no way to get multiple users by emails except users.list?
3- Also seems like there is no way to send messages to the multiple user at the same time (the content of the messages are different, those are depends on user data).
Sending a direct message by user ID works with chat.postMessage as a convenience, a shortcut. But it's the only method/API that allows you to use a user ID as a channel ID, so Slack warns developers away from relying on it in totality -- if you use conversations.open and the resultant conversation ID, it'll work for other methods like chat.update should you need to edit the message after sending it.
Slack doesn't offer many "lookup" APIs -- most things you'll want to look up require fetching an entire data set (like a list of users with all pages of users.list) and then filtering the results yourself. There are no APIs to look up multiple users at once via email address.
There is also no way to send the same direct message content to multiple users with a single request. In most cases, when an app is sending the same message to multiple users the best practice would be to use a channel to broadcast the message a single time, with the intended recipients as members of the channel.

How to send direct message in Slackbot

I would like to send messages to users through Slackbot, just like integration apps such as Zapier.
If I set the channel ID to the user ID it sends a 1:1 message showing up in the Apps tab, but what I really would like to do is to send a message in Slackbot, as I want to create a seamless experience for a Workflow I'm creating.
Then, if I try adding the Slackbot channel ID it returns channel_not_found and there's no way to add the App there.
My current bot token scope to send messages is: chat:write and I'm sending a message using chat.postMessage
Do I need a different scope? Different API method? I've tried going through some other questions/answers, but they look outdated

How to query in a Event Driven Microservice architecture?

Let suppose the following simple UC based on a CQRS architecture:
We have a backend managing a Business Object, let says a Movie.
This backend is composed of 2 Microservices: a CommandManager (Create/Update/Delete Movie) and a QueryManager (Query Movie)
We have a frontend that offer a web page for creating a new Movie and this action lead automatically to another web page describing the Movie.
A simple way to do that is:
A web page collect movie information using a form and send them to the frontend.
The frontend make a POST request to the CommandManager
The CommandManager write the new movies to the datastore and return the movie key
The frontend make a GET using this key to the QueryManager
The QueryManager looks for the Movie in the Datastore using the key and return it.
The frontend deliver the page with the Movie Information.
Ok, now I want to transform this UC in a more Event Driven way. Here is the new flow:
A web page collect movie information using a form and send them to the frontend.
The frontend write a Message in the BUS with the new movie information
The CommandManager listen the BUS and create the new movies in the datastore. Eventually, it publish a new message in the BUS specifying that a new Movie has been created.
At this point, the frontend is no more waiting for a response due to the fact that this kind of flow is asynchronous. How could we complete this flow in order to forward the user to the Movie Information Web page? We should wait that the creation process is done before querying the QueryManager.
In a more general term, in a asynchronous architecture based on bus/event, how to execute Query used to provide information in a web page?
In addition to #VoiceOfUnreason's answer,
If the two microservices are RESTFul, the CommandManager could return a 202 Accepted with a link pointing to the resource that will be created in the future. The client could then poll that resource until the server responds with a 200 OK.
Another solution would be that the CommandManager would return a 202 Accepted with a link pointing to a command/status endpoint. The client would poll that endpoint until the status is command-processed (including the URL to the the actual resource) or command-failed (including a descriptive message for the failure).
These solutions could be augmented by sending the status of all processed commands using Server Sent Events. In this way, the client gets notified without polling.
If the client is not aware that the architecture is asynchronous, a solution is to use an API gateway that blocks the client's request until the upstream microservice processes the command and then to respond with the complete resource's data.
At this point, the frontend is no more waiting for a response due to the fact that this kind of flow is asynchronous. How could we complete this flow in order to forward the user to the Movie Information Web page? We should wait that the creation process is done before querying the QueryManager.
Short answer: make the protocol explicit.
Longer answer: a good place to look for inspiration here is HTTP.
The front end makes a POST to the origin server; as a result the origin server places a message on the queue and sends a response back.
The representation sent with this response ought to describe the request's current status and point to (or embed) a status monitor that can provide the user with an estimate of when the request will be fulfilled.
The client can then poll the endpoint to find out what progress has been made.
For instance, the endpoint might be a query into the data store, that looks for evidence that the command manager has processed the original command; or it might be an endpoint that is watching the bus for the MovieCreated message, and changes its answer based on whether or not it has seen that.
It may help clarify things to look into idempotent request handling; when the Command Manager pulls a message off of its queue, how does it know if it has previously processed a copy of that message? Your polling endpoint should be able to use the same information to let the consumer know that the message has been successfully processed.
In addition to #Constantin Galbenu's answer, I would like to put in my two cents.
I would strongly advise you to look at a microservices pattern called "BFF" (Backend-For-Frontend) pattern. Instead of having a thick API gateway doing all the work, you can have an API per use-case. For Example: In your case, you can an API called "CreateMovieBFFHandler" which would receive the POST request from front-end and then this guy would coordinate with other things in the system like message queues, events etc. to track the status of the submitted request. UI might have a protocol with this BFFhandler that if the response doesn't come back in X seconds, then the front-end would consider it as failure and if this handler is able to get a successfully processed messaged from message queue or "MovieCreated" event for this key, then it could send a 200 OK back and then you can redirect the page to call write side and then populate the UI.
Useful Link: https://samnewman.io/patterns/architectural/bff/

How to restrict access on Websockets?

I'm trying to figure out how Websockets works. I read some articles, tutorials, etc and I have a pretty basic understanding of how it works, but there is one element that I can't understand how to implement.
My idea is the following : One user will load a "customer" page containing all informations of that customer + a discussion thread. If an other user load that same page, they will be able to discuss in real time and if one user update the data of the customer, the second one will see the update.
The thing that is bugging me, is how can I allow users to access a customer data, but by checking that they can access it (for example, users can access the customer of their group, not all customers)
How can I be sure that the current user will access a customer he has the right (in the websocket)?
Thank you for your help!
Think of the websocket connection itself as a separate thing. A socket used by a client can subscribe to many different events.
What you're describing is topics. When the websocket connection is established, you send a message using whatever socket framework you're using to subscribe to a topic. For example, it could be a topic called customer-123. (A analogy for a topic, is a chat room)
Your application logic (server side) will verify that the currently logged in user has permission to access customer 123, and if so, permits them to join this topic. If you don't do this, it would be trivial for users to listen to any messages relating to any data.
Whenever a user updates any data that is relevant to customer 123, a message is posted to that topic. And thus, any user who is in that topic will receive the message.
An socket might subscribe to many many topics for each customer they open in your app. And topics can be combined and managed in groups depending on how you want to send messages.
In a typical large app, it's common to have a websocket subscribe to topics like user-123, team-456 by default so the server can send messages to them individually or to the entire team to which they are a member of.
For example, if a user updates customer-123, I might send a full data object to the customer-123 topic, and if customer 123 belongs to team-456, I would also send a small notification object like 'User 789 has updated customer 123' to the entire team (which is what powers Facebooks feed like system).
As your app grows, you'll use services like notification hubs to manage the fact that there could be thousands of topics each with thousands of subscribers.
The best thing to do is share a session ID and set up authentication token policies between your web application and your socket session. You could set up your own policy middleware to check the session ID.
You aren't really clear about how you're trying to accomplish this. If you're using express/socket.io, you can use this module: https://www.npmjs.com/package/express-socket.io-session
Hope this helps!
Like any other production application, you need authentication (who is allowed to use the app) and authorization (what functionality can a authenticated user perform). Authorization (ie, access control - ACL) is probably more precisely what you are looking for. Your app has to consult an authorization subsystem to see if the current user has access permission to edit/view another user's information.
This is not a trivial concern for many applications; security and privacy are important aspects of any web-based (distributed) application.

Spring websocket get user subscription from stomp id

Using Spring 4.0.4 I made a DisconnectHandler that implements ApplicationListener on SessionDisconnectEvent.
I can get the sessionid from the event but how do I get a list of the subscriptions for that sessionid, i.e the user?
There is currently no way to get a list of subscriptions for a user. You can keep track of subscription messages as they arrive (not very hard to do). We do have a ticket to make this easier https://jira.spring.io/browse/SPR-12029.

Resources