Challenge:
I would like to use SailsJS, and be able to join a room, by means of socket.io, and receive unsolicited messages from this room, not just when one enters or leaves the room but also receive objects.
So several clients connect to the server.
Afterwards broadcast (initiated from the server) messages/objects to every room and thus everey connected socket in this room.
I maybe could just send every connected socket a message, but dearly would like a example on how to do this with SailsJS 0.10, and a elegant method in the SailsJS 0.10 way.
I am looking at : https://github.com/balderdashy/sailsChat, but I think this is to close to the models themselves, with like e.g: autosubscribe: ['destroy', 'update']
In my opinion this should be more loosely coupled, and not so tied to the model itself.
Thanks in advance!
I.
The purpose of the SailsChat example is to demonstrate how Sails JS resourceful pubsub can take a lot of hassle out of socket messaging when you are mainly concerned with sending messages about models. The fact that you can make a full-featured chat app in Sails with very little back-end code is what makes it impressive. For situations where resourceful pubsub is not appropriate--or if you just plain don't want to use it--Sails exposes lower-level methods on the sails.sockets namespace. The docs are pretty clear on how they work.
To join a socket to an arbitrary room, do sails.sockets.join(<socket>, <roomName>), where <socket> is either a raw socket (probably from req.socket or a socket ID).
To broadcast a message to all sockets in a room, do sails.sockets.broadcast(<roomName>, <data>).
These and more methods are described in detail in the Sails JS documentation.
I'm just starting with SailsJS, and already a big fan.
I need to find out if this is also scalable with e.g. Heroku or other flavors of SAAS providers, but seems not that hard.
So just a follow up on what I did with SailsJS 0.10:
Server-side:
Made a controller with the following:
join: function (req, res) {
if (req.isSocket === true) {
sails.sockets.join(req.socket, 'mysecretroom');
return res.send(200, 'joined');
}
return res.send(200);
},
sendToRoom: function( req, res ) {
if (req.isSocket === true ) {
sails.sockets.broadcast('mysecretroom', 'messageevent', {message:'Listen very carefully, I'll shall say this only once..!'});
}
return res.send(200);
}
Client-side:
io.socket.on('messageevent', function (data) {
console.log(data);
})
+1 kudos #sgress454!
Thanks!
Related
I'm looking for a solution that will have the backend publish an event to the frontend as soon as a modification is done on the server side. To be more concise I want to emit a new List of objects as soon as one item is modified.
I've tried implementing on a SpringBoot project, that uses Reactive Web, MongoDB which has a #Tailable cursor that publish an event as soon as the capped collection is modified. The problem is that the capped collection has some limitation and is not really compatible with what I want to do. The thing is I cannot update an existing element if the new one has a different size(as I understood this is illegal because you cannot make a rollback).
I honestly don't even know if it's doable, but maybe I'm lucky and I'll run into a rocket scientist right here that will prove otherwise.
Thanks in advance!!
*** EDIT:
Sorry for the vague question. Yes I'm more focused on the HOW, using the Spring Reactive framework.
When I had a similar need - to inform frontend that something is done on the backend side - I have used a message queue.
I have published a message to the queue from the backend and the frontend consumed the message.
But I am not sure if that is what you're looking for.
if you are using webflux with spring reactor, I think you can simply have a client request with content-type as 'text/event-stream' or 'application/stream+json' and You shall have API that can produce those content-type. This gives you SSE model without too much effort.
#GetMapping(value = "/stream", produces = {MediaType.TEXT_EVENT_STREAM_VALUE, MediaType.APPLICATION_STREAM_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
public Flux<Message> get(HttpServletRequest request) {
Just as an idea - maybe you need to use a web socket technology here:
The frontend side (I assume its a client side application that runs in a browser, written in react, angular or something like that) can establish a web-socket communication with the backend server.
When the process on backend finishes, the message from backend to frontend can be sent.
You can do emitting changes by hand. For example:
endpoint:
public final Sinks.Many<SimpleInfoEvent> infoEventSink = Sinks.many().multicast().onBackpressureBuffer();
#RequestMapping(path = "/sseApproach", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<SimpleInfoEvent>> sse() {
return infoEventSink.asFlux()
.map(e -> ServerSentEvent.builder(e)
.id(counter.incrementAndGet() + "")
.event(e.getClass().getName())
.build());
}
Code anywhere for emitting data:
infoEventSink.tryEmitNext(new SimpleInfoEvent("any custom event"));
Watch out of threads and things like "subscribeOn", "publishOn", but basically (when not using any third party code), this should work good enough.
I'm setting up a new mqtt conection in my app but there is a problem when i would like to create the main connection of mqtt.
I'm using mqtt.js.
I've tried all what is done in MQTT documentation but nothing happens..
mqttFunction(){
var mqtt = require('mqtt');
var client = mqtt.connect([{host: 'localhost', port: '1883'},]);
client.subscribe('presence')
client.on('message', function (topic, message) {
console.log(message);
});
}
I expect the output of the mqtt broker to be 'ON' when i asked it to respond.
The error is: ERROR ReferenceError: process is not defined
The documentation you followed is intended for Node.js and various other back-end JavaScript frameworks. Even though it uses NPM, Ionic ultimately produces a front-end framework, and its applications run a bit differently.
For example, Ionic programs may not have a global process variable like Node.js. mqtt.js expects this variable, with code like:
if (commist.parse(process.argv.slice(2)) !== null){...}
You could declare a process object, and get past this particular error. Other obstacles could come up.
var process = {env : {NODE_ENV: 'production'}}
If there are still issues with that, you could try the instructions for browser usage, which point to a specially compiled version, like https://unpkg.com/mqtt#3.0.0/dist/mqtt.min.js. I have had less luck with mqtt.js in the browser, and you may want an alternative like web-mqtt-cient / Paho if more complex connections are involved.
I'm trying to figure out how to use socket.io alongside of my react/redux application, and seeing how much I can optimize when doing so. So, on the server I have a pretty basic setup with the sockets you can see here :
store.subscribe(() => {
io.emit('state', store.getState().toJS());
});
io.on('connection', (socket) => {
socket.emit('state', store.getState().toJS());
socket.on('action', function (action) {
action.headers = socket.request.headers;
store.dispatch(action);
});
});
So the only thing out of the ordinary is I was just sticking the request headers onto the actions for use later. What I would like to try and achieve is something like this -
io.connections[i].emit('state')
and add
socket.on('state', (action) => {
socket.emit('state', getUserSpecificState(store));
});
The idea is this would allow me to loop through all the connections, and then use that connection's socket to call for the specific user at the time. I don't know if something like this is possible, and am looking for some possible feedback in handling sending back only user specific information back. It would also be cool to only send back the part of the state changed by the action (and not the whole state), and then have the front end store assemble the state. Any/all input is more than welcomed, thanks!
Looks like it's not redux's issue to handle this logic, you put it in some module and connect to state using middleware or just by using state object "from the outside". Speaking of state management, what are you trying to implement? Looks like case for some CRDT thing like swarm.js or diffsync.
I'm having some issues with the newest version of sails.js (0.11.0). It stated in github that plain socket.io code will be accepted and ran in sails.js; however, I am simply trying to emit a message from a client when they click on something like so:
$('#myBtn').on('click', function(){
io.socket.emit('message', {
message: {
subject: subject
},
sender: id
});
});
I end up getting an "Uncaught TypeError: undefined is not a function" on the line of io.socket.emit() aka emit is not a function of io.socket.
Here are some references that I have looked at:
https://github.com/balderdashy/sails/issues/2397
http://www.tysoncadenhead.com/blog/getting-started-with-socket-io#.VQCFjvnF9tU
I have a feeling with the updated version of sails, instead of emitting a message I should be doing something along the lines of:
io.socket.post('/user/message', data, function(data, jwres) {
});
Something concerns me with the following answer here:
Sending session specific messages with socket.io and sails.js
It states "class rooms" are being deprecated along with publishCreate, publishDestroy, introduce, and obituary.
So do I follow a Pub/Sub paradigm, re-write my more "socket-io-ish" code to utilize sails Blueprints & Pub/Sub, or continue in my socket-io fashion?
Is there another way of emitting a message from client using sails?
You are correct in that the recommended way of communicating with the server via sockets is to use the RESTful socket client methods. The benefit is that you can use the regular Sails routing and controller/action architecture for socket communication instead of having to support a whole other layer of subscription and event-handling on the backend. This is one of the main reasons why #mikermcneil originally created Sails. Two things to note:
You can use req.isSocket in your controller action to determine whether the request is coming from a socket, and
You can get the raw, underlying socket.io instance on the client with io.socket._raw, which will have the emit method. But again, this is not the recommended practice.
I am trying to implement a proof of concept service bus using MassTransit. I have three applications which need to communicate changes of a common entity type between each other. So when the user updates the entity in one application, the other two are notified.
Each application is configured as follows with their own queue:
bus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.ReceiveFrom("msmq://localhost/app1_queue");
sbc.UseSubscriptionService("msmq://localhost/subscription");
sbc.UseControlBus();
sbc.Subscribe(subs =>
{
subs.Handler<IMessage1>(IMessage1_Received);
});
});
There is also a subscription service application configured as follows:
subscriptionBus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.ReceiveFrom("msmq://localhost/subscription");
});
var subscriptionSagas = new InMemorySagaRepository<SubscriptionSaga>();
var subscriptionClientSagas = new InMemorySagaRepository<SubscriptionClientSaga>();
subscriptionService = new SubscriptionService(subscriptionBus, subscriptionSagas, subscriptionClientSagas);
subscriptionService.Start();
The problem is that when one of the applications publishes a message, all three applications receive it (including the original sender).
Is there any way to avoid this (without resorting to adding the application name to the message)?
Thanks,
G
So MassTransit is a pub/sub system. If you publish a message, everyone registered to receive it will. If you need only some endpoints to receive it, then you really need to directly send. It's just how this works.
You could include the source in your message and discard messages that aren't of interest to you. If you implement the Consumes.Accept interface, I think the Accept method would allow you to do so easily without mixing that into the normal consumption code.