草庐IT

c++ - 将 C++ 对象包装到 Node 插件中的 v8 对象

coder 2024-02-22 原文

我目前正在用 C++ 编写一个 Node 插件,我遇到了一个问题,我需要创建并返回一个 v8 数组,其中填充了 v8 包装的 C++ 对象实例。

目前,代码看起来像这样

v8::Handle<v8::Value> Controller::nodeArray(const v8::Arguments& args)
{
    v8::HandleScope scope;

    Controller* controller= ObjectWrap::Unwrap<Controller>(args.This());
    const std::vector<Foobar*>* foobars = controller->getFoobars();
    unsigned int foobarCount = foobars->size();

    v8::Handle<v8::Array> foobarsArray = v8::Array::New(foobarCount);
    std::vector<Foobar*>::const_iterator foobar = foobars->begin();

    for(unsigned int i = 0; i < foobarCount; i++)
    {
        // Need to create a v8 Object that wraps a single instance of a 
        // Foobar object in "foobars"

        // Then push the object to the v8 Array?
        // foobarsArray->Set(i, [some Foobar instance]);
        snake++;
    }

    return foobarsArray;
}

但是,我在 for 循环中尝试了几种不同的方法,但均无济于事。我应该怎么做呢?

Foobar 和 SuperFoo

这里是Foobar中定义的Init初始化器和nodeNew构造函数,以及Foobar的头文件code> 和 SuperFoo.

#define BUILDING_NODE_EXTENSION

#ifndef FOOBAR_H_
#define FOOBAR_H_

#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <node.h>
#include <string>
#include <vector>

#include <iostream>

#include "EnvironmentObject.h"
#include "SuperFoo.h"
#include "Grid.h"
#include "GridSection.h"
#include "Point.h"
#include "Teams.h"
#include "Vector.h"

class SuperFoo;
class Grid;

class Foobar : public SuperFoo
{
public:
    Foobar();
    virtual ~Foobar();
    Foobar(int id, const Point& location, const int& team, const Grid& world);
    Foobar(const Foobar& snake);

    // Node Implementation
    static void Init(v8::Handle<v8::Object> target);

private:
    // Node Implementation
    static v8::Handle<v8::Value> nodeNew(const v8::Arguments& args);
    static v8::Handle<v8::Value> nodeGetID(const v8::Arguments& args);
    static v8::Handle<v8::Value> nodeGetTeam(const v8::Arguments& args);
    static v8::Handle<v8::Value> nodeGetState(const v8::Arguments& args);
    static v8::Handle<v8::Value> nodeGetVelocity(const v8::Arguments& args);

    int id_;
    int team_;
    int state_;
    Vector* velocity_;
    const Grid* world_;
};

#endif /* FOOBAR_H_ */
#define BUILDING_NODE_EXTENSION

#ifndef GAMEOBJECT_H_
#define GAMEOBJECT_H_

#include <string>

#include <node.h>

#include "Point.h"
#include "Vector.h"

class SuperFoo : public node::ObjectWrap
{
public:
    SuperFoo()
        : collidable_(true), stationary_(true) {}
    virtual ~SuperFoo();
    SuperFoo(const std::string& type, const Point& position);
    SuperFoo(const SuperFoo& object);

    virtual bool collide(SuperFoo& object) = 0;

    Point getPosition() const;
    std::string getType() const;

    void setPosition(const Point& position);

    bool isCollidable() const;
    bool isStationary() const;

    void setCollidable(bool coolide);
    void setStationary(bool stationary);

protected:
    Point* position_;

private:
    // Node Implementation
    static v8::Handle<v8::Value> nodeGetPosition(const v8::Arguments& args);

    std::string* type_;
    bool collidable_;
    bool stationary_;
};

#endif /* SUPERFOO_H_ */
void Foobar::Init(v8::Handle<v8::Object> target)
{
    // Prepare constructor template
    v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(nodeNew);
    tpl->SetClassName(v8::String::NewSymbol("Foobar"));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);
    // Prototype functions
    tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("getID"), v8::FunctionTemplate::New(nodeGetID)->GetFunction());
    tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("getVelocity"), v8::FunctionTemplate::New(nodeGetVelocity)->GetFunction());
    tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("getState"), v8::FunctionTemplate::New(nodeGetState)->GetFunction());

    v8::Persistent<v8::Function> constructor = v8::Persistent<v8::Function>::New(tpl->GetFunction());
    target->Set(v8::String::NewSymbol("Foobar"), constructor);
}

v8::Handle<v8::Value> Foobar::nodeNew(const v8::Arguments& args)
{
    v8::HandleScope scope;

    int id = args[0]->NumberValue();
    Point* position = ObjectWrap::Unwrap<Point>(args[1]->ToObject());
    int team = args[2]->NumberValue();
    Grid* world = ObjectWrap::Unwrap<Grid>(args[3]->ToObject());

    Foobar* foobar = new Foobar(id, *position, team, *world);

    foobar->Wrap(args.This());

    return args.This();
}
v8::Handle<v8::Value> Controller::nodeSpawnFoobar(const v8::Arguments& args)
{
    Controller* gridController = ObjectWrap::Unwrap<Controller>(args.This());

    int team = args[0]->NumberValue();
    gridController->createFoobar(foobarID++, team);

    return v8::Undefined();
}

void Controller::spawnFoobar(int id, int team)
{
    Point createPosition;
    if(team == Teams::kBlue)
    {
        createPosition = world_->getAreaPosition(Teams::kBlue)->getPosition();
    }
    else if (team == Teams::kRed)
    {
        createPosition = world_->getAreaPosition(Teams::kRed)->getPosition();
    }

    int xh = createPosition.get()[0] - EnvironmentObject::kAreaSize / 2
    int yh = createPosition.get()[1] + EnvironmentObject::kAreaSize / 2;

    int x = (rand() % EnvironmentObject::kAreaSize) + xh;
    int y = (rand() % EnvironmentObject::kAreaSize) + yh - EnvironmentObject::kAreaSize;

    foobars_->push_back(new Foobar(id, Point(x, y), team, *world_));
}

Javascript 调用

这是该方法的使用方式

this.update = function() {
    if([some event]) {
        controller.createFoobar();
        console.log(this.getFoobars())
    }
}

this.getFoobars = function() {
    var foobars = controller.getFoobars();
    var foobarsArray = new Array();

    for(i = 0; i < foobars.length; i++) {
        var foobar = foobar[i];

        var position = foobar.getPosition();
        var posX = position.getX();
        var posY = position.getY();
        var positionPoint = new Point(posX, posY);

        var velocity = foobar.getVelocity();
        var toX = velocity.getToX();
        var toY = velocity.getToX();
        var velocityVector = new Vector(toX, toY);

        var foobarObj = {
                id: foobar.getID(),
                team: foobar.getTeam(),
                position: positionPoint,
                velocity: velocityVector,
                state: foobar.getState()
        }

        foobarsArray.push(foobarObj);
    }

    return miniSnakesArray;
};

最佳答案

只要 Foobar 实例已使用您的 nodeNew 构造函数创建,或者更具体地说,只要 Wrap 已在某些时候被调用点在对象上,你应该可以这样做:

v8::Local<v8::Array> foobarsArray = v8::Array::New(foobarCount);

for(unsigned int i = 0; i < foobarCount; i++){
  foobarsArray->Set(i, (*foobars)[i]->handle_);
}

return scope.Close(foobarsArray);

Node 也有一些帮助工具来缩短你的 Init:

// Prototype functions
node::SetPrototypeMethod(tpl, "getID", nodeGetID);
node::SetPrototypeMethod(tpl, "getVelocity", nodeGetVelocity);
node::SetPrototypeMethod(tpl, "getState", nodeGetState);

在您的情况下,由于您不是直接在 JS 中创建 Foobar 实例,因此您希望保存对构造函数的引用,并使用它来创建新实例,而不是调用新的 Foobar。如果您考虑您编写的代码,Foobar 对 JavaScript 方面的知识知之甚少,因为它是 v8 构造函数对象,它知道如何使用正确的方法创建对象。

// Save a global reference
v8::Persistent<v8::Function> foobarConstructor;

// Inside 'Init', assign the constructor to the global
foobarConstructor = v8::Persistent<v8::Function>::New(tpl->GetFunction());
target->Set(v8::String::NewSymbol("Foobar"), foobarConstructor);


// Then instead of 'Foobar* instance = new Foobar'
int argc = 4;
Local<Value> argv[] = {
  // The 4 arguments.
};
v8::Local<v8::Object> instance = foobarConstructor->NewInstance(argc, argv);

关于c++ - 将 C++ 对象包装到 Node 插件中的 v8 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16329491/

有关c++ - 将 C++ 对象包装到 Node 插件中的 v8 对象的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  7. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  8. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  9. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  10. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

随机推荐