For examples like this:
https://bravenewmethod.com/2011/02/21/node-js-tls-client-example/
Or in my own code:
client = tls.connect(port, host, tlsOptions, function() {
}
client.on('end', function(data) {
}
When do these lifecycle methods get actually called? In the documentation, https://nodejs.org/api/tls.html, I don't see anything about it.
You need to be looking in the doc for the Net module for a TCP socket which a TLS socket inherits from. tls.TLSSocket is a subclass of net.Socket. This is a common issue with documentation for a class hierarchy where you don't realize that lots of things are documented in the base class documentation. In that doc, it says this for the end event:
Emitted when the other end of the socket sends a FIN packet, thus
ending the readable side of the socket.
By default (allowHalfOpen is false) the socket will send a FIN packet
back and destroy its file descriptor once it has written out its
pending write queue. However, if allowHalfOpen is set to true, the
socket will not automatically end() its writable side, allowing the
user to write arbitrary amounts of data. The user must call end()
explicitly to close the connection (i.e. sending a FIN packet back).
For the close event, that same doc says this:
Emitted once the socket is fully closed. The argument had_error is a
boolean which says if the socket was closed due to a transmission
error.
This means that the close event comes after the end event since the socket may be still at least partially open when the end event is received.
So, you will get end when the other side has told you it is no longer accepting data (receipt of FIN packet) and you will get close when the socket is now completely closed.
The tls.TLSSocket class is an instance of the net.Socket class. You can find additional information about the events and methods it has in that documentation (https://nodejs.org/api/net.html#net_class_net_socket). Most likely, net.Socket#end if I had to guess.
Related
I am unable to get two users chatting to each other despite reducing the complexity and the potential code that could have caused the issue.
I am able to emit to all connected sockets so I have established it's not an issue in context of emit/on structure but rather; coming from the way i'm handling the private socket ids.
I have tried various versions of trying to send the private message to the correct socket id; I have tried older ways such as socket.to and the current way from the docs which is io.to(sockid).emit('event' message); all these variations have been unable to help me. I have consoled out the socket id I have on my Angular client side by printing console.log('THIS IS MY SOCKET '+this.socket.id) and comparing it to the value I have in Redis using redis-cli and they both match perfectly every time which doesn't give me too much to go on.
problem arises here:
if (res === 1) {
_active_users.get_client_key(recipient)
.then(socket_id => {
console.log('======='+io.sockets.name)
console.log('I am sending the message to: '+ recipient + 'and my socket id is'+ socket_id)
// socket.to(socket_id)socket.emit('incoming', "this is top secret"
io.of('/chat').to(socket_id).emit('incoming', "this is top secret")
})
.catch(error => {
console.log("COULD NOT RETRIEVE KEY: " + error)
})
Here is the link to the pastebin with more context:
https://pastebin.com/fYPJSnWW
The classes I import are essentially just setters and getters for handling the socket id you can think of them as just a worker class that handles Redis actions.
Expected: To allow two clients to communicate based on just their socket ids.
Actual:
am able to emit to all connected sockets and receive the expected results but the problem arises when trying to send to a specific socket id from a unknown reason.
Issue was coming from my front end.. I hope nobody has a headache like this! but here is what happened; when you're digging your own hole you often don't realise how deep you got yourself if you don't take the time to look around. I had two instances of the sockets. I instantiated both and used the one to connect and the other to send the message; which of course you cannnot do if you want things to work properly. So what I did was created only one instance of the socket in and and passed that ref of the socket around where I needed it which is ( sendMessage(username, socket) getMessage(socket)
ngOnInit(
this.socket = io.connect('localhost:3600',{
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax : 5000,
reconnectionAttempts: Infinity});
Currently, I'm testing my Node.js, Socket.io server on localhost and on devices connected to my router.
For testing purposes, I would like to simulate a delay in sending messages, so I know what it'll be like for users around the world.
Is there any effective way of doing this?
If it's the messages you send from the server that you want to delay, you can override the .emit() method on each new connection with one that adds a short delay. Here's one way of doing that on the server:
io.on('connection', function(socket) {
console.log("socket connected: ", socket.id);
// override the .emit() method
const emitFn = socket.emit
socket.emit = (...args) => setTimeout(() => {
emitFn.apply(socket, args)
}, 1000)
// rest of your connection handler here
});
Note, there is one caveat with this. If you pass an object or an array as the data for socket.emit(), you will see that this code does not make a copy of that data so the data will not be actually used until the data is sent (1 second from now). So, if the code doing the sending actually modifies that data before it is sent one second from now, that would likely create a problem. This could be fixed by making a copy of the incoming data, but I did not add that complexity here as it would not always be needed since it depends upon how the caller's code works.
An old but still popular question. :)
You can use either "iptables" or "tc" to simulate delays/dropped-packets. See the man page for "iptables" and look for 'statistic'. I suggest you make sure to specify the port or your ssh session will get affected.
Here are some good examples for "tc":
http://www.linuxfoundation.org/collaborate/workgroups/networking/netem
Take this code, where f is a stream that has an event 'body', which calls the listeners with a m -- which is itself a stream emitting events:
f.on('message', function(m) {
m.on('body', function(stream, info) {
var b = '';
stream.on('data', function(d) {
b += d;
});
stream.on('end', function() {
if (/^header/i.test(info.which))
msg.header = Imap.parseHeader(b);
else
msg.body = b;
});
});
m.on('attributes', function(attrs) {
msg.attrs = attrs;
msg.contentType = partID[1];
});
});
f.on('end', function() {
if (hadErr)
return;
cb(undefined, msg);
});
The backend is emitting a 'message' event, passing it a m object. The code then listens to the events body and attributes. It's all straightforward except that my little brain is in a bit of a crisis (I am not used to dealing with streams). Especially: how is the backend emitting from the f and m objects, to guarantee that events are indeed called at the right time?
Specifically:
How would f have to be coded, in general terms, in order to make sure that mm doesn't emit till m.on('body', function(stream, info) { is called?
Does a listener need to be added with on() before the event is emitted in order for it to be caught?
If so, does that mean that f and m will emit events after the code here has registered?
If the backend is supposed to guarantee that b.emit('end') is called after m.emit('end'), how is that even supposed to happen really, still guaranteeing that on() is called before any one of the events are emitted?
OK I am 100% confused about this matter. I am obviously missing something basic and crucial, and I am not even able to ask the right questions because of this...! (Apologies)
Does a listener need to be added with on() before the event is emitted in order for it to be caught?
Yes.
If so, does that mean that f and m will emit events after the code here has registered?
No, events are not queued anywhere. If nothing is listening for them, they will be lost. I think that's what you're asking anyway... f and m don't seem to emit events in your code.
If the backend is supposed to guarantee that b.emit('end') is called after m.emit('end'), how is that even supposed to happen really, still guaranteeing that on() is called before any one of the events are emitted?
b is a string in your example? I'm not sure what you're asking here.
Think of it differently. When .on is called, a function is subscribed to a channel of messages. Those messages are already flowing before that function is subscribed, and will continue to flow if that function is unsubscribed. .on and .removeListener() just set the subscription status for a particular function.
Events can be emitted even if nothing is listening for them. Events can fire all the time and if nothing is listening, they just don't go anywhere. (An exception to this are the error events built into Node.js, which are turned into real exceptions if there isn't an error handler.)
How would f have to be coded, in general terms, in order to make sure that mm doesn't emit till m.on('body', function(stream, info) { is called?
I still don't follow specifically what you're asking, since none of the code you show emits anything. But, you wouldn't really want to do this. You need to be setting up your event handlers before opening a stream, or doing whatever you are doing that causes the events to be fired.
You might be getting confused on the ordering of event handling on new objects. In Node.js, there is a rule... Never emit directly from your constructor. Always use nextTick() or similar. This way, after instantiation, any code to attach itself to event handlers can do so before the events are emitted.
Also, if you are using streams, consider using the readable event so that the stream remains paused until you're ready to read from it. Pull vs. push.
(I am using node-amqp and rabbitmq server.)
I am trying to guess why I have a close event if something goes wrong. For example, If I try to open a a connection to a queue (with bad parameters) I receive an error event. That it is perfect ok.
But, after any error I will receive also a close connection (in that case, maybe because close the failed socket to the queue). And after that, auto-reconnect and I receive the (initial) ready event.
The problem:
connection.on('ready', function() {
do_a_lot_of_things
}).on(error, function(error){
solve_the_problem
});
if something goes wrong, I receive the error, but then "ready" event and it will re do_a_lot_of_things. Is my approach wrong?
best regards
You can use connection.once('ready', function () { … }) (see the documentation), which will execute the handler only on the first event.
I am currently using Client.stopMediaSessions(). Is this correct? From what I read in the documentation, and see in the examples, this seems to be the right way to do it.
This should stop both local and remote streams, correct?
What event(s) is/are fired when stopMediaSessions() is called? From my logs, it doesn’t seem that the handler for mediaStream:end is being called. Should it be? Or is enterState:closed the only event fired? Or are both fired?
My question has to do with removing the <video> elements from the DOM – both for the remote and local elements. In your example for MediaStream in the API Reference, the addStream() function handles both mediaStream:start and mediaStream:end events. However, when using this to add both local and remote streams, you can’t count on the mediaElement variable in the mediaStream:end handler because nothing ties that var to the stream, so you don’t know which element to do a removeChild() on.
Anyway, that’s not a big deal. I am just curious what the sequence of events is when a stopMediaSessions() is called; from that I can ensure the right <video> element is being removed.
But in general, I do want to know what the correct way is to hang up/terminate a video call among a set of participants.
Thanks a lot!
client.stopMediaSessions() will stop all vline.MediaSessions for the given vline.Client, so yes, it will "hang up" a call.
To "hang up" an audio/video session with a specific user (vline.Person), you can use Person.stopMedia().
A vline.MediaSession can have local and remote vline.MediaStreams associated with it, so by stopping a vline.MediaSession you will implicitly stop all vline.MediaStreams associated with it.
Since client.stopMediaSessions() is stopping all of the vline.MediaSession's (and therefore vline.MediaStream's), you should get both a mediaStream:end event (from the vline.MediaStream) and a enterState:closed event (from the vline.MediaSession).
For adding and removing <video> elements and keeping track of them, I'd suggest doing something similar to what the vLine shell example does. It uses the unique MediaStream ID to name the div that it puts the <video> element in:
mediaSession.on('mediaSession:addLocalStream mediaSession:addRemoteStream', function(event) {
var stream = event.stream;
// guard against adding a local video stream twice if it is attached to two media sessions
if ($('#' + stream.getId()).length) {
return;
}
$('#video-wrapper').append(elem);
});
// add event handler for remove stream events
mediaSession.on('mediaSession:removeLocalStream mediaSession:removeRemoteStream', function(event) {
$('#' + event.stream.getId()).remove();
});