Function Not Returning Value

I have a function in a node that searches for and returns the line of a text file. It does what it should, but the output is only assigned to the variable inside the function. Additionally, the debug output seems to indicate that the line after I call the function is being called first. I've tried all sorts of things the past several hours but can't put my finger on what the problem is.

Thank you,
Chris

function Get_Message(File, msgNumber){
    // Check if the file exists.
    if (parseInt(msgNumber) != 0) {
        fs.access(File, fs.F_OK, (err) => {
            if (err) {
                node.warn(err);
            }

            // File exists.
            var line = msgNumber - 1;
        
            var myInterface = readline.createInterface({
                input: fs.createReadStream(File)
            });

            var lineno = 0;

            myInterface.on('line', function (line) {
                lineno++;
            
                if (lineno == msgNumber){
                    var Message = line;
                    node.warn(Message)
                }
            });
        })
    }
    
    return Message;
}
if (parseInt(Payload["Error"]) != 0){
    File = "/home/pi/Documents/Machines/" + Machine + "/" + Machine + " Errors.txt";
    var Message = Get_Message(File, Payload["Error"])||null;
    node.warn("1: " + Message);
} else {
    File = "/home/pi/Documents/Machines/" + Machine + "/" + Machine + " Status.txt";
    var Message = Get_Message(File, Payload["Status"])||null;
    node.warn("2: " + Message);
}

MWSnap 2021-08-17, 13_47_15

fs.access is an async function so return will not work. Use node.send instead.

Ps, why are you using fs in a function instead of the built-in/for purpose "file in" node?

fs.access seems to be asynchronous. You will have to wait for it to be finished then use node.send(msg) vs just returning the message.

edit
@Steve-Mcl beat me to the answer

1 Like

I'm deciding which file just before I call the function. It seems far more efficient to read the file at the time I need it and continue processing from where I'm at, rather than daisy-chaining even more nodes.

Thank you, guys. I'll take a look at node.send.

It doesn't look like that's going to work, either. Thanks anyways. I'll keep hunting for a solution.

It will. Or... You could use a function to calculate a filename, set msg.filename, pass the msg to a file in node & do it the graphical/node-red way

I know you said it's not efficient but unless you are doing many thousands of operations, the difference will be almost nothing.

Fair enough. I did what you suggested and am reading the file. I now have a rather large string I need to parse. I was looking to grab a specific line from the file.

you can set your File-in node to
image

and process each line separately
or if you want to join all lines to an array then
after your File-in use a Join node

image

You could use an exec node and grep to find the line

Thank you. I used a function to set my filename and combine the results into an array. I had to create a global variable in the same function to get the original msg.payload to the end function. All set. Thanks, guys!

if you needed to pass the original payload further down the flow line ..
since you used a function .. you could simply transfer the original payload to another msg property to protect it .. because yes, the payload would have been replaced by the file-in node's output.

msg.originalPayload = RED.util.cloneMessage(msg.payload)
[EDIT] we clone the msg with NR util to avoid by reference

Set file-in to image

Context is useful also.

Doesn't it need cloning first?

1 Like

Very good point .. i always forget about that :wink:
(I'll edit the above post)

1 Like

I ended up doing most of the processing in the first node and assigning everything to a new object that I made global. All worked out well. Thank you! I appreciate it!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.