nodejs / help

:sparkles: Need help with Node.js? File an Issue here. :rocket:
1.44k stars 276 forks source link

Need help with embedded API #4400

Open rayzorben opened 1 month ago

rayzorben commented 1 month ago

Node.js Version

v20.9.0

NPM Version

10.7.0

Operating System

Windows 11

Subsystem

v8

Description

I am looking for generic help here. Let me explain what I am trying to do. I have already compiled with the example embedded API, but it just doesn't do what I am looking for.

I have a file, mega.js with 2 exported functions MegaSend and MegaRecv. These functions rely on other node code that is in the list of requires within that file.

My goal is to load node into my C++ application, and load this file into memory so that I can simply call those 2 functions in this file and receive a return result (string). I would need to keep this in memory as state is maintained within the javascript file across multiple calls.

Any help appreciated.

Minimal Reproduction

Here is the code I hve now put together from example and ChatGPT but I can't get it to work.


char* CallMegaMegaSend(const char* buf, std::string& result) {
    v8::Isolate *isolate = v8::Isolate::GetCurrent();

    CallJavaScriptFunction("MegaMegaSend", buf, result);
}

void CallJavaScriptFunction(const char *functionName, const char *data, std::string &result)
{
    v8::Isolate *isolate = v8::Isolate::GetCurrent();

    // Enter the persistent context
    v8::HandleScope handleScope(isolate);
    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, persistentContext);
    v8::Context::Scope contextScope(context);

    // Get the global object
    v8::Local<v8::Object> global = context->Global();

    // Get the function object
    v8::Local<v8::Value> value = global->Get(v8::String::NewFromUtf8(isolate, functionName).ToLocalChecked());
    v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value);

    // Convert the data to a V8 string
    v8::Local<v8::String> jsData = v8::String::NewFromUtf8(isolate, data).ToLocalChecked();

    // Call the JavaScript function
    v8::Local<v8::Value> argv[1] = {jsData};
    v8::Local<v8::Value> jsResult = function->Call(context, global, 1, argv).ToLocalChecked();

    // Convert the result to a C++ string
    v8::String::Utf8Value utf8Value(isolate, jsResult->ToString(isolate));
    result = *utf8Value;
}

void LoadNode() {
    v8::Isolate *isolate = v8::Isolate::New();
    {
        v8::Isolate::Scope isolate_scope(isolate);
        v8::HandleScope handle_scope(isolate);

        // Create a persistent context
        CreatePersistentContext(".\\mega.js");
    }
}

void CreatePersistentContext(const char *filename)
{
    v8::Isolate *isolate = v8::Isolate::GetCurrent();

    // Create a new context
    v8::Local<v8::Context> context = v8::Context::New(isolate);

    // Enter the context and set it as the persistent context
    v8::Context::Scope contextScope(context);
    persistentContext.Reset(isolate, context);

    // Read the JavaScript file
    std::ifstream file(filename);
    if (!file)
    {
        return;
    }

    std::string scriptSource((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());

    // Compile the source code
    v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, scriptSource.c_str()).ToLocalChecked();
    v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();

    // Run the script to initialize the functions
    script->Run(context);
}

Output

No response

Before You Submit

preveen-stack commented 1 month ago

C++ embedder API# Node.js provides a number of C++ APIs that can be used to execute JavaScript in a Node.js environment from other C++ software https://nodejs.org/api/embedding.html

rayzorben commented 1 month ago

Yes I am aware of that, I already referenced that document in my question to show that I am aware of it.

I have already compiled with the example embedded API, but it just doesn't do what I am looking for.

I do not see how that explains how to load a javascript file, and execute a function within it. I see that it can possibly execute a javascript file itself, but not how to interact with it.

bncdemo commented 1 month ago

Node.js Version

v20.9.0

NPM Version

10.7.0

Operating System

Windows 11

Subsystem

v8

Description

I am looking for generic help here. Let me explain what I am trying to do. I have already compiled with the example embedded API, but it just doesn't do what I am looking for.

I have a file, mega.js with 2 exported functions MegaSend and MegaRecv. These functions rely on other node code that is in the list of requires within that file.

My goal is to load node into my C++ application, and load this file into memory so that I can simply call those 2 functions in this file and receive a return result (string). I would need to keep this in memory as state is maintained within the javascript file across multiple calls.

Any help appreciated.

Minimal Reproduction

Here is the code I hve now put together from example and ChatGPT but I can't get it to work.

char* CallMegaMegaSend(const char* buf, std::string& result) {
    v8::Isolate *isolate = v8::Isolate::GetCurrent();

    CallJavaScriptFunction("MegaMegaSend", buf, result);
}

void CallJavaScriptFunction(const char *functionName, const char *data, std::string &result)
{
    v8::Isolate *isolate = v8::Isolate::GetCurrent();

    // Enter the persistent context
    v8::HandleScope handleScope(isolate);
    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, persistentContext);
    v8::Context::Scope contextScope(context);

    // Get the global object
    v8::Local<v8::Object> global = context->Global();

    // Get the function object
    v8::Local<v8::Value> value = global->Get(v8::String::NewFromUtf8(isolate, functionName).ToLocalChecked());
    v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value);

    // Convert the data to a V8 string
    v8::Local<v8::String> jsData = v8::String::NewFromUtf8(isolate, data).ToLocalChecked();

    // Call the JavaScript function
    v8::Local<v8::Value> argv[1] = {jsData};
    v8::Local<v8::Value> jsResult = function->Call(context, global, 1, argv).ToLocalChecked();

    // Convert the result to a C++ string
    v8::String::Utf8Value utf8Value(isolate, jsResult->ToString(isolate));
    result = *utf8Value;
}

void LoadNode() {
    v8::Isolate *isolate = v8::Isolate::New();
    {
        v8::Isolate::Scope isolate_scope(isolate);
        v8::HandleScope handle_scope(isolate);

        // Create a persistent context
        CreatePersistentContext(".\\mega.js");
    }
}

void CreatePersistentContext(const char *filename)
{
    v8::Isolate *isolate = v8::Isolate::GetCurrent();

    // Create a new context
    v8::Local<v8::Context> context = v8::Context::New(isolate);

    // Enter the context and set it as the persistent context
    v8::Context::Scope contextScope(context);
    persistentContext.Reset(isolate, context);

    // Read the JavaScript file
    std::ifstream file(filename);
    if (!file)
    {
        return;
    }

    std::string scriptSource((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());

    // Compile the source code
    v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, scriptSource.c_str()).ToLocalChecked();
    v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();

    // Run the script to initialize the functions
    script->Run(context);
}

Output

No response

Before You Submit

  • [x] I have looked for issues that already exist before submitting this
  • [x] My issue follows the guidelines in the README file, and follows the 'How to ask a good question' guide at https://stackoverflow.com/help/how-to-ask

This is a generic V8 code, NOT a nodejs code.