`

Addons

阅读更多
Addons是动态链接共享对象。它们能提供和c及c++库的粘合。API(当前)是比较复杂的,包含了一些库的知识:
●V8 JavaScript,一个C++库。被用来作为Javascript接口:建立对象,调用方法等等。在v8.h头文件中有说明文档(在Node源树中的deps/v8/include/v8.h),它也可在线查看。
●libuv,C事件loop库。任何时候谁需要等待一个文件描述符变成可读,等待一个计时器,或者等待一个信号来接收什么将需要和libuv接口。换言之,如果你执行任何I/O,libuv将需要被使用到。
●内部Node库。Most importantly is the node::ObjectWrap class which you will likely want to derive from.
●其他。 Look in deps/ for what else is available.

Node静态编译它的所有依赖到可执行文件。当编译你的模块,你不需要担心链接到任何这些库。

Hello world
让我们建立一简单的Addon,它是一个C++,等价于下面的Javascript代码:
exports.hello = function() { return 'world'; };

首先我们建立一个文件hello.cc:
#include <node.h>
#include <v8.h>

using namespace v8;

Handle<Value> Method(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New("world"));
}

void init(Handle<Object> target) {
  target->Set(String::NewSymbol("hello"),
      FunctionTemplate::New(Method)->GetFunction());
}
NODE_MODULE(hello, init)


注意所有的Node addons必须导出一个初始化函数:
void Initialize (Handle<Object> target);
NODE_MODULE(module_name, Initialize)


在NODE_MODULE后没有分号因为它不是一个函数(请看node.h)。
module_name 需要对应最后的二进制文件名(去掉node后缀)。

源代码需要构建到hello.node中,二进制Addon。为了做到这个我们建立一个名为binding.gyp文件,它以类似JSON的格式描述了建立你的模块的配置。这个文件通过node-gyp编译。
{
  "targets": [
    {
      "target_name": "hello",
      "sources": [ "hello.cc" ]
    }
  ]
}


下一步是为当前平台生成适当的项目构建文件。为此使用node-gypconfigure。

现在你将会在build/ directory目录下有一个Makefile(在Unix平台上)或者vcxproj文件(在Windows平台上)。下一步调用node-gyp build命令。

现在你有你的编译过的.node bindings文件了!编译过的bindings在build/Release/里。

你现在能在Node项目hello.js中使用字节addon了,通过将require指向刚建立的hello.node模块:
var addon = require('./build/Release/hello');

console.log(addon.hello()); // 'world'


更多的信息请参看下面的模式或https://github.com/arturadib/node-qt 中一个产品项目。

Addon 模式
下面是一些addon模式来帮助你开始。请参考在线v8参考帮助中的各种v8调用,和v8的Embedder指南对使用的几个概念的解释,比如handles,scopes,function templates等待。

为了去使用这些示例你需要使用node-gyp编译它们。建立如下的binding.gyp文件:
{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon.cc" ]
    }
  ]
}


在某些情况下有不止一个.cc文件,只需添加文件的名字到来源数组,例如:
"sources": ["addon.cc", "myexample.cc"]


现在你的binding.gyp准备就绪,你能配置和组件addon:
$ node-gyp configure build


函数参数

以下模式演示了如何从JavaScript函数调用读取参数并返回一个结果。这是主要的,和唯一必要的源代码addon.cc:
#define BUILDING_NODE_EXTENSION
#include <node.h>

using namespace v8;

Handle<Value> Add(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    ThrowException(Exception::TypeError(String::New("Wrong arguments")));
    return scope.Close(Undefined());
  }

  Local<Number> num = Number::New(args[0]->NumberValue() +
      args[1]->NumberValue());
  return scope.Close(num);
}

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("add"),
      FunctionTemplate::New(Add)->GetFunction());
}

NODE_MODULE(addon, Init)


你能使用下面的Javascript片段来测试它:
var addon = require('./build/Release/addon');

console.log( 'This should be eight:', addon.add(3,5) );


回调
你能传递Javascript函数到C++函数中并在那里执行它们。下面是addon.cc:
#define BUILDING_NODE_EXTENSION
#include <node.h>

using namespace v8;

Handle<Value> RunCallback(const Arguments& args) {
  HandleScope scope;

  Local<Function> cb = Local<Function>::Cast(args[0]);
  const unsigned argc = 1;
  Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) };
  cb->Call(Context::GetCurrent()->Global(), argc, argv);

  return scope.Close(Undefined());
}

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("runCallback"),
      FunctionTemplate::New(RunCallback)->GetFunction());
}

NODE_MODULE(addon, Init)


使用下面的Javascript片段进行测试:
var addon = require('./build/Release/addon');

addon.runCallback(function(msg){
  console.log(msg); // 'hello world'
});


对象工厂
通过这个addon.cc模式,你能在C++函数中建立和返回新对象,它返回的新对象有msg属性,它echo传递到createObject()的字符串:
#define BUILDING_NODE_EXTENSION
#include <node.h>

using namespace v8;

Handle<Value> CreateObject(const Arguments& args) {
  HandleScope scope;

  Local<Object> obj = Object::New();
  obj->Set(String::NewSymbol("msg"), args[0]->ToString());

  return scope.Close(obj);
}

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("createObject"),
      FunctionTemplate::New(CreateObject)->GetFunction());
}

NODE_MODULE(addon, Init)


在Javascript中进行测试:
var addon = require('./build/Release/addon');

var obj1 = addon.createObject('hello');
var obj2 = addon.createObject('world');
console.log(obj1.msg+' '+obj2.msg); // 'hello world'


函数工厂
这种模式演示了如何创建并返回一个包装了一个c++函数的JavaScript函数:
#define BUILDING_NODE_EXTENSION
#include <node.h>

using namespace v8;

Handle<Value> MyFunction(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New("hello world"));
}

Handle<Value> CreateFunction(const Arguments& args) {
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(MyFunction);
  Local<Function> fn = tpl->GetFunction();
  fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous

  return scope.Close(fn);
}

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("createFunction"),
      FunctionTemplate::New(CreateFunction)->GetFunction());
}

NODE_MODULE(addon, Init)


如下测试:
var addon = require('./build/Release/addon');

var fn = addon.createFunction();
console.log(fn()); // 'hello world'


Wrapping C++对象
这里我们将为 C++ object/class MyObject 建立一个wrapper,该object可以通过新的操作符在JavaScript中实例化。首先准备主要的模块addon.css:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

void InitAll(Handle<Object> target) {
  MyObject::Init(target);
}

NODE_MODULE(addon, InitAll)


然后在myobject.h 中从node::ObjectWrap继承你的包装器:
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <node.h>

class MyObject : public node::ObjectWrap {
 public:
  static void Init(v8::Handle<v8::Object> target);

 private:
  MyObject();
  ~MyObject();

  static v8::Handle<v8::Value> New(const v8::Arguments& args);
  static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args);
  double counter_;
};

#endif


然后在myobject.cc中实现你想要公开的各种方法。这里我们公开方法plugOne,则添加它到constructor's prototype:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

MyObject::MyObject() {};
MyObject::~MyObject() {};

void MyObject::Init(Handle<Object> target) {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  // Prototype
  tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"),
      FunctionTemplate::New(PlusOne)->GetFunction());

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

Handle<Value> MyObject::New(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = new MyObject();
  obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
  obj->Wrap(args.This());

  return args.This();
}

Handle<Value> MyObject::PlusOne(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This());
  obj->counter_ += 1;

  return scope.Close(Number::New(obj->counter_));
}


如下测试:
var addon = require('./build/Release/addon');

var obj = new addon.MyObject(10);
console.log( obj.plusOne() ); // 11
console.log( obj.plusOne() ); // 12
console.log( obj.plusOne() ); // 13


Factory of wrapped objects
这是有用的,例如当你希望能够创建本地对象又不在Javascript中使用new操作符显式地实例化它们。
var obj = addon.createObject();
// instead of:
// var obj = new addon.Object();


让我们在addon.cc中注册我们的createObject 函数:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

Handle<Value> CreateObject(const Arguments& args) {
  HandleScope scope;
  return scope.Close(MyObject::NewInstance(args));
}

void InitAll(Handle<Object> target) {
  MyObject::Init();

  target->Set(String::NewSymbol("createObject"),
      FunctionTemplate::New(CreateObject)->GetFunction());
}

NODE_MODULE(addon, InitAll)


在myobject.h中我们现在介绍静态方法NewInstance,它负责对象的实例化(也就是它做了JavaScript中的new的工作):
#define BUILDING_NODE_EXTENSION
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <node.h>

class MyObject : public node::ObjectWrap {
 public:
  static void Init();
  static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args);

 private:
  MyObject();
  ~MyObject();

  static v8::Persistent<v8::Function> constructor;
  static v8::Handle<v8::Value> New(const v8::Arguments& args);
  static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args);
  double counter_;
};

#endif


The implementation is similar to the above in myobject.cc:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

MyObject::MyObject() {};
MyObject::~MyObject() {};

Persistent<Function> MyObject::constructor;

void MyObject::Init() {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  // Prototype
  tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"),
      FunctionTemplate::New(PlusOne)->GetFunction());

  constructor = Persistent<Function>::New(tpl->GetFunction());
}

Handle<Value> MyObject::New(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = new MyObject();
  obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
  obj->Wrap(args.This());

  return args.This();
}

Handle<Value> MyObject::NewInstance(const Arguments& args) {
  HandleScope scope;

  const unsigned argc = 1;
  Handle<Value> argv[argc] = { args[0] };
  Local<Object> instance = constructor->NewInstance(argc, argv);

  return scope.Close(instance);
}

Handle<Value> MyObject::PlusOne(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This());
  obj->counter_ += 1;

  return scope.Close(Number::New(obj->counter_));
}


如下测试:
var addon = require('./build/Release/addon');

var obj = addon.createObject(10);
console.log( obj.plusOne() ); // 11
console.log( obj.plusOne() ); // 12
console.log( obj.plusOne() ); // 13

var obj2 = addon.createObject(20);
console.log( obj2.plusOne() ); // 21
console.log( obj2.plusOne() ); // 22
console.log( obj2.plusOne() ); // 23


Passing wrapped objects around
除了包装并返回c++对象,你能通过使用Node's node::ObjectWrap::Unwrap helper function展开它们来pass them around。在下面的addon.cc我们引入一个函数add(),它可以接纳两个MyObject对象:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

Handle<Value> CreateObject(const Arguments& args) {
  HandleScope scope;
  return scope.Close(MyObject::NewInstance(args));
}

Handle<Value> Add(const Arguments& args) {
  HandleScope scope;

  MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
      args[0]->ToObject());
  MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
      args[1]->ToObject());

  double sum = obj1->Val() + obj2->Val();
  return scope.Close(Number::New(sum));
}

void InitAll(Handle<Object> target) {
  MyObject::Init();

  target->Set(String::NewSymbol("createObject"),
      FunctionTemplate::New(CreateObject)->GetFunction());

  target->Set(String::NewSymbol("add"),
      FunctionTemplate::New(Add)->GetFunction());
}

NODE_MODULE(addon, InitAll)


为了使事情有趣的我们在myobject.h中引入一个公共方法,这样我们就可以在对象展开后探测私有值:
#define BUILDING_NODE_EXTENSION
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <node.h>

class MyObject : public node::ObjectWrap {
 public:
  static void Init();
  static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args);
  double Val() const { return val_; }

 private:
  MyObject();
  ~MyObject();

  static v8::Persistent<v8::Function> constructor;
  static v8::Handle<v8::Value> New(const v8::Arguments& args);
  double val_;
};

#endif


myobject.cc的实现和前面类似:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

using namespace v8;

MyObject::MyObject() {};
MyObject::~MyObject() {};

Persistent<Function> MyObject::constructor;

void MyObject::Init() {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  constructor = Persistent<Function>::New(tpl->GetFunction());
}

Handle<Value> MyObject::New(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = new MyObject();
  obj->val_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
  obj->Wrap(args.This());

  return args.This();
}

Handle<Value> MyObject::NewInstance(const Arguments& args) {
  HandleScope scope;

  const unsigned argc = 1;
  Handle<Value> argv[argc] = { args[0] };
  Local<Object> instance = constructor->NewInstance(argc, argv);

  return scope.Close(instance);
}


如下测试:
var addon = require('./build/Release/addon');

var obj1 = addon.createObject(10);
var obj2 = addon.createObject(20);
var result = addon.add(obj1, obj2);

console.log(result); // 30
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    repository.xbmc-addons-chinese-2.0.0.zip

    标题中的"repository.xbmc-addons-chinese-2.0.0.zip"是一个针对KODI媒体中心的中文插件库的压缩包,版本号为2.0.0。这个压缩包包含了多款专为中国用户设计的KODI插件,旨在提升KODI在中文环境下的用户体验和功能...

    fastadmin-addons.zip

    而Fastadmin-addons,则是其专门为实现插件化开发设计的类库,它使得开发者能够轻松地创建、安装和管理各种插件,极大地提升了开发效率和系统的可扩展性。 在PHP世界里,插件是一种常见的模块化开发方式,它允许...

    repository.xbmc-addons-chinese-1.2.1.zip

    标题“repository.xbmc-addons-chinese-1.2.1.zip”揭示了这是一个与XBMC(Xbox Media Center)相关的软件资源包,版本号为1.2.1,并且是针对中文用户定制的。XBMC是一款开源的媒体中心软件,后来更名为Kodi,允许...

    org\vaadin\addons\dcharts-widget

    【标题】"org\vaadin\addons\dcharts-widget" 是一个与Vaadin框架相关的插件,主要用于在Web应用中提供数据图表的展示功能。Vaadin是一个流行的Java开发框架,用于构建用户界面,尤其是企业级的B2B应用程序。dcharts...

    repository.xbmc-addons-chinese-2.0.1.zip亲测可用kodi中文插件库下载

    标题中的“repository.xbmc-addons-chinese-2.0.1.zip”是一个针对Kodi的中文插件库的压缩包,版本号为2.0.1。Kodi是一款开源的媒体中心软件,允许用户在各种设备上管理和播放多媒体内容,如视频、音乐和图片。这个...

    Ultimate_VC_Addons_WordPress_Ultimate_VC_Addons_wpaddon_Vc_php_源

    【标题】"Ultimate_VC_Addons_WordPress_Ultimate_VC_Addons_wpaddon_Vc_php_源" 提供的是WordPress插件Ultimate VC Addons的PHP源代码,这是一款功能强大的Visual Composer扩展插件,用于增强WordPress网站的构建...

    Maxthon Browser Shopping Addons

    "Maxthon Browser Shopping Addons" 提供了一系列专为网购爱好者设计的插件和扩展,旨在优化用户的在线购物体验。这些插件通常包含了价格比较、优惠券查找、购物助手等功能,帮助用户在浏览商品时获取更多信息,从而...

    Beginning Lua with World of Warcraft Addons

    《Beginning Lua with World of Warcraft Addons》作为一本专注于Lua语言与魔兽世界插件开发的教程,不仅适合初学者入门,也为有一定基础的开发者提供了深入学习和实践的机会。通过本书的学习,你将能够掌握一门强大...

    前端开源库-redux-addons

    而"前端开源库-redux-addons"则关注于Redux的扩展插件,这些插件旨在进一步提升Redux的功能和易用性。 Redux本身提供了一个中心化的状态容器,帮助开发者管理应用中的状态。然而,随着项目规模的增长,纯使用Redux...

    onethink多图上传插件Addons(修复flashbug)可放大,删除图片

    《Onethink多图上传插件Addons:修复Flash Bug及增强功能解析》 Onethink是一款基于ThinkPHP框架的开源内容管理系统,它为开发者提供了丰富的功能和灵活的扩展性。在开发过程中,图片上传是常见的需求之一。针对这...

    Ultimate Addons for Visual Composer 3.16.10

    《Ultimate Addons for Visual Composer 3.16.10》是一款专为WPBakery Page Builder设计的强大扩展插件,旨在进一步丰富其内置功能,提供更多的设计元素和选项,帮助用户创建出更具视觉冲击力和专业感的网页内容。...

    My Firefox Addons

    【标题】:“Firefox Common Addons” 【描述】:“Firefox Common Addons”指的是在Firefox浏览器上常用的扩展或插件。这些工具通常由开发者社区创建,旨在增强浏览器的功能,提高用户浏览体验,或者提供特定的...

    PyPI 官网下载 | tensorflow_addons-0.11.2-cp35-cp35m-win_amd64.whl

    资源来自pypi官网,解压后可用。 资源全名:tensorflow_addons-0.11.2-cp35-cp35m-win_amd64.whl

    ext-addons-7.6.0-trial

    "ext-addons-7.6.0-trial" 是一个与ExtJS库相关的扩展包,它提供了7.6.0版本的附加组件。ExtJS是一个基于JavaScript的富客户端框架,广泛用于构建复杂的、数据驱动的Web应用程序。这个"trial"版可能意味着这是一个...

    kodi中文插件最新2022 repository.xbmc-addons-chinese-2.0.0

    kodi中文插件最新2022 repository.xbmc-addons-chinese-2.0.0

    前端开源库-react-addons-create-fragment

    "react-addons-create-fragment"是React早期版本的一个加载项,它提供了创建和管理多个子元素集合的能力,而不会在DOM中插入额外的节点。这个加载项在React 16版本之后被废弃,取而代之的是更现代和优化的API,如`...

    org.vaadin.addons.dcharts-widget-0.10.0-dcharts-widget-0.10.0.jar

    org.vaadin.addons.dcharts-widget-0.10.0-dcharts-widget-0.10.0.jar

    前端开源库-react-addons-pure-render-mixin

    "react-addons-pure-render-mixin"是React的一个官方加载项,它提供了一个优化性能的策略,特别是在处理大型复杂应用时。 标题中的“react-addons-pure-render-mixin”是React的一个关键特性,用于帮助开发者实现更...

    开源ERP项目Gooderp_Addons.zip

    git remote add osbzr https://github.com/osbzr/gooderp_addons.git环境就准备好了把远程分支的合并到自己的分支1.把对方的代码拉到你本地。git fetch osbzr2.合并对方代码git merge osbzr/master3.最新的...

    asterisk-addons-1.6.1-current.tar.gz

    asterisk-addons-1.6.1-current.tar.gzasterisk-addons-1.6.1-current.tar.gzasterisk-addons-1.6.1-current.tar.gz

Global site tag (gtag.js) - Google Analytics