I have here a simple program using coffeescript which creates a server on a Raspberry pi, and this receives data from a python script running on a Windows machine on the same network, does some calculations with that data and sends back the results.
What I would like to do, is keep the server open, running and accepting data until a parameter sent by the python script asks it to close.
To try this, I have created a loop which blocks the code until these flags are set; however, this is, well, blocking the code so the flags are not being set (the python script is not even able to connect). So I imagine I need to use some sort of asynchronous control here/promises.
# Functions
process_data = (data) ->
double_value: data * 2
triple_value: data * 3
clean_up_actions = () ->
console.log "Cleaning up..."
# Create server
net = require('net')
domain = '10.1.1.28'
port = 9001
program_complete = false
clean = false
console.log("Creating server...")
server = net.createServer (socket) ->
console.log "#{socket.remoteAddress} has connected"
# When data is received, do something and send back a response
socket.on 'data', (data) ->
console.log("Data received...")
if not program_complete
incoming_data = JSON.parse(data)
some_useful_value = incoming_data["some_useful_value"]
result = process_data(some_useful_value)
socket.write JSON.stringify(result)
# Check if end of program
program_complete = incoming_data["end_program"]
if program_complete
clean_up_actions()
clean = true
console.log "Listening to #{domain}:#{port}"
server.listen port, domain
console.log("Waiting until complete...")
loop
break if program_complete and clean
console.log "--- PROGRAM FINISHED ---"
To test this, I have used Q.delay(10000)
instead of the loop, and it works how I expect it to work (I get a connection and can pass data back and forth not problem), except instead of exiting when the end_program
is set to True, it will exit after 10 seconds (as expected).
...
# console.log("Waiting until complete...")
# loop
# break if program_complete and clean
# console.log "--- PROGRAM FINISHED ---"
Q = require('q')
Q.delay(10000).then ->
console.log "Done"
.finally ->
console.log('--- PROGRAM END ---')
process.exit(0)
My question is, how can I use a promise or other asynchronous control (like Q.delay(n)
) but instead of delaying for a time, it waits until these flags are set.
If interested, or want to test it, the python code is below
import socket
import json
import time
REMOTE_HOST = '10.1.1.28'
REMOTE_PORT = 9001
# Create a socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to the remote host and port
sock.connect((REMOTE_HOST, REMOTE_PORT))
# Send some data
data_dictionary = {
'some_useful_value' : 21,
'end_program' : False
}
data_to_send = json.dumps(data_dictionary).encode('utf-8')
sock.send(data_to_send)
print(sock.recv(1024))
time.sleep(0.5)
# Send some data, but this time, end
data_dictionary = {
'some_useful_value' : 13,
'end_program' : True
}
data_to_send = json.dumps(data_dictionary).encode('utf-8')
sock.send(data_to_send)
print(sock.recv(1024))
time.sleep(0.5)
# Terminate
sock.close()
CodePudding user response:
There are probably a few ways you can achieve this, where we wait until your flag end_program
or clean
from your code is set to true by your socket.on 'data'
method.
At the end of the script, you can use a function that continuously returns a promise until a certain condition is met (in this case, the flag clean
is set).
The Q library you are using should suffice as I believe its .delay
function is async. For example, in the below code, the function checks the flag every second, and if the flag is not set, the function will call itself again, checking after another second. If the flag is set, we can then move on to the next part of the code.
This may look something like this, using the variable clean
as your flag:
waitForFlag = () ->
Q.delay(1000).then ->
if (clean)
console.log "Condition met! We can move on"
else
# if condition isn't met, check again in one second
waitForFlag()
# Call function
waitForFlag().then ->
process.exit(0)
CodePudding user response:
My question is, how can I use a promise or other asynchronous control (like Q.delay(n)) but instead of delaying for a time, it waits until these flags are set.
I think the short answer is no, or at least not without digging into some more esoteric stuff like interrupts. But you can approximate that "manually" by setting up a short wait, checking if the value is set and then either waiting again or exiting the wait-status and moving on with the rest of your logic based on the result of that check.
I'm not familiar with the Q library you're importing here (and invoking with Q.delay
) but I think you're on the right path. In the general case I think what you want to do is use setInterval
or setTimeout
to essentially "yield" the execution for some relatively short time then check if the value has been set. I imagine that Q.delay
is using setTimeout
or similar internally.
Here's a rough sketch of what I mean:
# here is the flag we'll wait to be set
the_flag = null
# here is an arbitrary callback method that represents
# the "action" to take once the flag is set
the_callback = (flag)->
console.log "#{(new Date()).toISOString()}: the_flag is now set to:", flag
# we'll keep a handle to the value returned by setInterval
# so we can cancel it later.
interval_id = null
# here's the method that checks if the flag has been set
# and responds accordingly
check_if_flag_is_set = ()->
if the_flag?
# it *is* set now, so clear the interval and callback
clearInterval(interval_id)
interval_id = null
the_callback(the_flag)
else
console.log "#{(new Date()).toISOString()}: the flag is not yet set, still waiting..."
# now just kick off the interval to invoke the "check"
# method every 3 seconds
interval_id = setInterval( check_if_flag_is_set, 3000 )
Now if/when the value of the_flag
is set in some asynchronous code the check_if_flag_is_set
method will detect it and report the result to the_callback
. Note that the setInterval
wait period is non-blocking - other code can and will execute while we're waiting on the next invocation of check_if_flag_is_set
.
That said, the network i/o interaction is also non-blocking, so if the flag is being set by some data being written to the socket you don't really need an extra layer of asynchronous, non-blocking waiting via setInterval
. You could just wait for the on('data',handler)
or similar event to be emitted by your network listener.