Extension Node.js
Méthode Init
Afin de créer une extension Node.js, nous devons écrire un nœud qui hérite de la classe C++ de ::ObjectWrap. ObjectWrap implémente des méthodes publiques qui nous facilitent l'interaction avec Javascript
Écrivons d'abord le framework de base de la classe :
#include <v8.h> // v8 is the Javascript engine used by QNode #include <node.h> // We will need the following libraries for our GTK+ notification #include <string> #include <gtkmm.h> #include <libnotifymm.h> using namespace v8; class Gtknotify : node::ObjectWrap { private: public: Gtknotify() {} ~Gtknotify() {} static void Init(Handle<Object> target) { // This is what Node will call when we load the extension through require(), see boilerplate code below. } }; /* * WARNING: Boilerplate code ahead. * Thats it for actual interfacing with v8, finally we need to let Node.js know how to dynamically load our code. * Because a Node.js extension can be loaded at runtime from a shared object, we need a symbol that the dlsym function can find, * so we do the following: */ v8::Persistent<FunctionTemplate> Gtknotify::persistent_function_template; extern "C" { // Cause of name mangling in C++, we use extern C here static void init(Handle<Object> target) { Gtknotify::Init(target); } NODE_MODULE(gtknotify, init); }
Maintenant, nous devons écrire le code suivant dans notre Init () :
Déclarez le constructeur et liez-le à notre variable cible. var n = require("notification"); liera notification() à n:n.notification().
// Wrap our C++ New() method so that it's accessible from Javascript // This will be called by the new operator in Javascript, for example: new notification(); v8::Local<FunctionTemplate> local_function_template = v8::FunctionTemplate::New(New); // Make it persistent and assign it to persistent_function_template which is a static attribute of our class. Gtknotify::persistent_function_template = v8::Persistent<FunctionTemplate>::New(local_function_template); // Each JavaScript object keeps a reference to the C++ object for which it is a wrapper with an internal field. Gtknotify::persistent_function_template->InstanceTemplate()->SetInternalFieldCount(1); // 1 since a constructor function only references 1 object // Set a "class" name for objects created with our constructor Gtknotify::persistent_function_template->SetClassName(v8::String::NewSymbol("Notification")); // Set the "notification" property of our target variable and assign it to our constructor function target->Set(String::NewSymbol("notification"), Gtknotify::persistent_function_template->GetFunction());
Déclarez les attributs : n.title et n.icon.
// Set property accessors // SetAccessor arguments: Javascript property name, C++ method that will act as the getter, C++ method that will act as the setter Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("title"), GetTitle, SetTitle); Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("icon"), GetIcon, SetIcon); // For instance, n.title = "foo" will now call SetTitle("foo"), n.title will now call GetTitle()
Déclarez la méthode prototype : n.send()
// This is a Node macro to help bind C++ methods to Javascript methods (see https://github.com/joyent/node/blob/v0.2.0/src/node.h#L34) // Arguments: our constructor function, Javascript method name, C++ method name NODE_SET_PROTOTYPE_METHOD(Gtknotify::persistent_function_template, "send", Send);
Maintenant, notre méthode Init() devrait ressembler à ceci :
// Our constructor static v8::Persistent<FunctionTemplate> persistent_function_template; static void Init(Handle<Object> target) { v8::HandleScope scope; // used by v8 for garbage collection // Our constructor v8::Local<FunctionTemplate> local_function_template = v8::FunctionTemplate::New(New); Gtknotify::persistent_function_template = v8::Persistent<FunctionTemplate>::New(local_function_template); Gtknotify::persistent_function_template->InstanceTemplate()->SetInternalFieldCount(1); // 1 since this is a constructor function Gtknotify::persistent_function_template->SetClassName(v8::String::NewSymbol("Notification")); // Our getters and setters Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("title"), GetTitle, SetTitle); Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("icon"), GetIcon, SetIcon); // Our methods NODE_SET_PROTOTYPE_METHOD(Gtknotify::persistent_function_template, "send", Send); // Binding our constructor function to the target variable target->Set(String::NewSymbol("notification"), Gtknotify::persistent_function_template->GetFunction()); }
Il ne reste plus qu'à écrire les méthodes C++ que nous utilisons dans la méthode Init : New, GetTitle, SetTitle, GetIcon, SetIcon, Send
Méthode Constructeur : New()
La méthode New() crée une nouvelle instance de notre classe personnalisée (un objet Gtknotify), définit certaines valeurs initiales, puis renvoie le gestionnaire JavaScript de l'objet. C'est le comportement attendu de JavaScript appelant un constructeur à l'aide de l'opérateur new.
std::string title; std::string icon; // new notification() static Handle<Value> New(const Arguments& args) { HandleScope scope; Gtknotify* gtknotify_instance = new Gtknotify(); // Set some default values gtknotify_instance->title = "Node.js"; gtknotify_instance->icon = "terminal"; // Wrap our C++ object as a Javascript object gtknotify_instance->Wrap(args.This()); return args.This(); } getters 和 setters: GetTitle(), SetTitle(), GetIcon(), SetIcon()
Ce qui suit est principalement du code passe-partout qui se résume à une conversion de valeur entre C++ et JavaScript (v8).
// this.title static v8::Handle<Value> GetTitle(v8::Local<v8::String> property, const v8::AccessorInfo& info) { // Extract the C++ request object from the JavaScript wrapper. Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder()); return v8::String::New(gtknotify_instance->title.c_str()); } // this.title= static void SetTitle(Local<String> property, Local<Value> value, const AccessorInfo& info) { Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder()); v8::String::Utf8Value v8str(value); gtknotify_instance->title = *v8str; } // this.icon static v8::Handle<Value> GetIcon(v8::Local<v8::String> property, const v8::AccessorInfo& info) { // Extract the C++ request object from the JavaScript wrapper. Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder()); return v8::String::New(gtknotify_instance->icon.c_str()); } // this.icon= static void SetIcon(Local<String> property, Local<Value> value, const AccessorInfo& info) { Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder()); v8::String::Utf8Value v8str(value); gtknotify_instance->icon = *v8str; }
Méthode prototype : Send()
Nous extrayons d'abord la référence this de l'objet C++, puis utilisons les propriétés de l'objet pour créer la notification et l'afficher il.
// this.send() static v8::Handle<Value> Send(const Arguments& args) { v8::HandleScope scope; // Extract C++ object reference from "this" Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(args.This()); // Convert first argument to V8 String v8::String::Utf8Value v8str(args[0]); // For more info on the Notify library: http://library.gnome.org/devel/libnotify/0.7/NotifyNotification.html Notify::init("Basic"); // Arguments: title, content, icon Notify::Notification n(gtknotify_instance->title.c_str(), *v8str, gtknotify_instance->icon.c_str()); // *v8str points to the C string it wraps // Display the notification n.show(); // Return value return v8::Boolean::New(true); }
Compile extension
node-waf est un outil de construction utilisé pour compiler les extensions Node, qui est l'encapsulation de base de waf. Le processus de construction est configurable via un fichier appelé wscript.
def set_options(opt): opt.tool_options("compiler_cxx") def configure(conf): conf.check_tool("compiler_cxx") conf.check_tool("node_addon") # This will tell the compiler to link our extension with the gtkmm and libnotifymm libraries. conf.check_cfg(package='gtkmm-2.4', args='--cflags --libs', uselib_store='LIBGTKMM') conf.check_cfg(package='libnotifymm-1.0', args='--cflags --libs', uselib_store='LIBNOTIFYMM') def build(bld): obj = bld.new_task_gen("cxx", "shlib", "node_addon") obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"] # This is the name of our extension. obj.target = "gtknotify" obj.source = "src/node_gtknotify.cpp" obj.uselib = ['LIBGTKMM', 'LIBNOTIFYMM']
Maintenant, nous sommes prêts à commencer la construction, exécutez la commande suivante dans le répertoire de niveau supérieur :
node-waf configure && node-waf build
If tout Normalement, nous obtiendrons l'extension compilée, située à l'adresse : ./build/default/gtknotify.node Essayons :
$ node > var notif = require('./build/default/gtknotify.node'); > n = new notif.notification(); { icon: 'terminal', title: 'Node.js' } > n.send("Hello World!"); true
Le code ci-dessus affichera un message de notification dans le coin supérieur droit de votre. écran.
Intégré dans un package npm
C'est très cool, mais comment partager les résultats de vos efforts avec la communauté Node C'est l'objectif principal de npm ? : utilisation Il est plus facile à étendre et à distribuer.
Créer des packages d'extension npm est très simple. Tout ce que vous avez à faire est de créer un fichier package.json dans votre répertoire de niveau supérieur qui contient vos informations d'extension :
{ // 扩展的名称 (不要在名称中包含node 或者 js, 这是隐式关键字). // 这是通过require() 导入扩展的名称. "name" : "notify", // Version should be http://semver.org/ compliant "version" : "v0.1.0" // 这些脚本将在调用npm安装和npm卸载的时候运行. , "scripts" : { "preinstall" : "node-waf configure && node-waf build" , "preuninstall" : "rm -rf build/*" } // 这是构建我们扩展的相对路径. , "main" : "build/default/gtknotify.node" // 以下是可选字段: , "description" : "Description of the extension...." , "homepage" : "https://github.com/olalonde/node-notify" , "author" : { "name" : "Olivier Lalonde" , "email" : "olalonde@gmail.com" , "url" : "http://www.syskall.com/" } , "repository" : { "type" : "git" , "url" : "https://github.com/olalonde/node-notify.git" } }
Pour plus de détails sur le format package.json, la documentation peut être obtenue via npm help json Notez que la plupart des champs sont facultatifs
Vous pouvez désormais le faire dans votre niveau supérieur. répertoire via Exécutez npm install pour installer votre nouveau package npm. Si tout se passe bien, vous devriez pouvoir simplement charger votre extension var notify = require('your package name');. Un autre lien npm impératif utile est via Avec cette commande, vous peut créer un lien vers votre répertoire de développement, vous n'avez donc pas besoin d'installer/désinstaller à chaque fois que votre code change
Supposons que vous ayez écrit une extension intéressante, vous souhaiterez peut-être que le référentiel central npm soit publié en ligne. . Vous devez d'abord créer un compte :
$ npm adduser
Ensuite, retournez dans votre répertoire de codage racine et exécutez :
$ npm publish
Ça y est, votre package. peut désormais être installé par n'importe qui à l'aide de la commande npm install avec le nom de votre package.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!