Your Universal Remote Control Center
RemoteCentral.com
Philips Pronto Professional Forum - View Post
Previous section Next section Up level
Up level
The following page was printed from RemoteCentral.com:

Login:
Pass:
 
 

Topic:
Preventing socket function returning until ondata callback completes
This thread has 2 replies. Displaying all posts.
Post 1 made on Saturday August 22, 2020 at 18:26
peteS
Long Time Member
Joined:
Posts:
June 2003
19
I know this is likely a lack of core JS knowledge on my part, but can't work it out ...

I have a function which opens an async socket to my satellite box and uses onconnect and ondata to send command to the box. All works fine. The problem is that if I send multiple commands one after another, the callbacks from earlier commands haven't completed, so I end up with multiple sockets open and the server reaches a limit and stops accepting new connections. So, how to get over this. The obvious thing seems to be to try and turn the async socket into something that is more like a sync socket - don't return from the calling function until the callbacks are finished. But, that goes against the whole idea of callbacks and the async nature of javascript. Is this possible, or do I need to take a different approach. I can see something using a queue instead (put the commands onto a queue, at the end of the callback see if there's anything in the queue and if there is, call the connect command again) but that sounds messy (e.g. the first call would need to be different to call the function first time around).

What's the right way to approach this. At heart, I want to be able to send a number of commands to a server, but only open a single socket.

ta

pete S
Post 2 made on Saturday August 22, 2020 at 20:04
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,609
The queue is definitely the best approach.

Use an array for the queue. Do .push(entry) to add things to the end and .shift() to remove the first entry.

This is one way to do it. The queue just guarantees an ordered write.

var queue = [];
var buffer = '';
var activeCommand = null;

function sendSomething(toSend) {
queue.push(toSend);
sendNext();
}

function sendNext() {
if (activeCommand) {
return;
}

if (socket && socket.connected && queue.length) {
activeCommand = queue.shift();
socket.write(activeCommand);
}
}


function onConnect() {
// if any commands have been queued
sendNext();
}

function cleanupSocket() {
if (socket) {
if (socket.connected) {
try{socket.close();}catch(e){}
}
socket.onData = null;
socket.onIOError = null;
socket.onConnect = null;
socket = null;
}
}

function onIOError() {
cleanupSocket();
}

function onData() {
// within onData, 'this' and socket are one in the same.
buffer += this.read();
// process any data that was read.
// blah blah blah
// assume that if you received a message, server is ready for next command.
activeCommand = null;
// send next command.
sendNext();
}

Note that ideally, you might want to use a scheduleAfter() to clear activeCommand and then call sendNext Periodically in case the server does not respond.

Finally, the code above does not manage reconnects should the server close the socket. I leave that exercise up to you. I would recommend that in onIOError that you use scheduleAfter to do a reconnect.

Pete,

I edited the above after a re-read and also added onConnect and onIOError as an example.

I do what you ask specifically in my Denon TCP/IP module but as I use 2 queues (priority and background), the code is more complicated than needed for this purpose.

If you will be so kind as to email me at my address on profile, I can help you work out the details of how to use a single socket that reconnects as needed and also uses a queue to manage commands. Email me your PS Library or your config I will have a look. If you are in the USA, I don't mind having a phone call (or facetime) to talk through the details.

Last edited by Lyndel McGee on August 23, 2020 09:49.
Lyndel McGee
Philips Pronto Addict/Beta Tester
OP | Post 3 made on Sunday August 23, 2020 at 12:37
peteS
Long Time Member
Joined:
Posts:
June 2003
19
Hi Lyndel

Many thanks for the offer - that's incredibly kind. I'll email the library in a moment - be gentle with me on my coding - my proper programming days were cobol, fortran and a bit of C, and this has been hacked together through various bits of reading.

The protocol is reverse engineered via wireshark - it's not documented or publicly available.

I create a new instance in an activity event

var skyip = new com.sketch.sky.IPControl("kitchen");

then, I'll call a command

skyip.SendCommand("home");

On and Off are a bit different since I have to check first the current power state using a different port to get status as there are no distinct power commands, but after that, they also just use SendCommand, so it's there I'll need to build in the queue. The logic actually makes perfect sense with the queue - I'm glad my thoughts were on the right track at least.


Jump to


Protected Feature Before you can reply to a message...
You must first register for a Remote Central user account - it's fast and free! Or, if you already have an account, please login now.

Please read the following: Unsolicited commercial advertisements are absolutely not permitted on this forum. Other private buy & sell messages should be posted to our Marketplace. For information on how to advertise your service or product click here. Remote Central reserves the right to remove or modify any post that is deemed inappropriate.

Hosting Services by ipHouse