0

I am trying to read a file in the NAPI application and call the callback function to write it to the writestream in the nodejs application.

exmaple_Class.cpp

void readFromTransientFile(const Napi::CallbackInfo &info) 
{
    Napi::Env env = info.Env();
    Napi::HandleScope scope(env);

    Napi::Function cb = info[0].As<Napi::Function>();
    

    while ((this->actualClass_->pos() < this->actualClass_->size()) &&
               ((readLength = this->actualClass_->read((void *)tempBuffer, sizeof(tempBuffer))) > 0))
        {

            //cb.Call(env.Global(), {Napi::Buffer<char>::New(env, tempBuffer, sizeof(tempBuffer))});
            cb.Call(env.Global(), {Napi::String::New(env, tempBuffer)});

            writeTotal += readLength;
        }
    std::cout << "Done!" << std::endl;
}

exmaple_Class.js

const testAddon = require("./build/Release/testaddon.node");
const fs = require("fs");

const prevInstance = new testAddon.OtClass();
const writeStream = fs.createWriteStream("./downloads/lake.jpg");

  prevInstance.readFromTransientFile(
    function (msg) {
      console.log(">> received buffer from getFile: ", msg);
      console.log(">> typeof msg", typeof msg);
      writeStream.write(msg);
    }
  );

writeStream.end();

Limitation of C++ side function is that it cannot return value, so data has to return in the callback. The funny part is that if it is a text file, it works correctly but for other types of files like zip or jpeg, I get garbled data. If I pass a file descriptor to a C++ function and use UNIX write function, then I get the file. But I would like to send that data over HTTP using express as well. So what is going wrong? How can I correctly wrap and return binary data in NAPI objects.

neil_ruaro
  • 368
  • 3
  • 15

1 Answers1

0

For the future generations. Data encoding was the error. Binary data is represented as Byte Array, then convert it into Buffer for writeStreamer to consume.

fileReader.cpp

void functionexample::ReadRawFile(const Napi::CallbackInfo &info)
{
    Napi::Env env = info.Env();
    Napi::HandleScope scope(env);

    // nodejs callback
    Napi::Function cb = info[0].As<Napi::Function>();

    char *file_name = "lake.jpg";
    int i = 0;
    const int BLOCK_SIZE = 1024;
    char buffer[BLOCK_SIZE];
    ifstream ifs;

    ifs.open(file_name, ifstream::binary | ifstream::in);

    while (1)
    {
        memset(buffer, 0, BLOCK_SIZE);

        ifs.read(buffer, BLOCK_SIZE);

        cout << i << " | buffer size: " << ifs.gcount() << endl;
        i++;

        ///  PASSING DATA TO THE NODEJS APPLICATION
        ///  AS A BINARY ARRAY PPINTER POINTING TO THE buffer
        cb.Call(env.Global(), {Napi::ArrayBuffer::New(env, buffer, ifs.gcount())});

        ofs.write(buffer, ifs.gcount());
        if (!ifs)
            break;
    }

    ifs.close();
}

fileWriter.js

const fs = require("fs");
const testAddon = require("./build/Release/testaddon.node");

// Create a write streamer 
const wstream = fs.createWriteStream("./lake-copied-nodejs.jpg");

testAddon.readFile(function(msg) {
  // handle data encoding
  const buf = Buffer.alloc(msg.byteLength);
  const view = new Uint8Array(msg);
  for (var i = 0; i < buf.length; ++i) {
    buf[i] = view[i];
  }

  // write binary data to file
  wstream.write(buf);
});
wstream.close();

module.exports = testAddon;
  • Do you think it is possible to write persistent binary data on the c++ side, then reading that data again? Using only function calls on the JavaScript side, not using `require("fs")`? – Jesus Jimenez Nov 23 '22 at 00:09