Node.js-Erweiterung
Init-Methode
Um eine Node.js-Erweiterung zu erstellen, müssen wir schreiben ein Knoten, der die C++-Klasse von ::ObjectWrap erbt. ObjectWrap implementiert öffentliche Methoden, die uns die Interaktion mit Javascript erleichtern.
Schreiben wir zunächst das Grundgerüst der Klasse:
#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); }
Jetzt müssen wir den folgenden Code in unsere Init schreiben ()-Methode:
Deklarieren Sie den Konstruktor und binden Sie ihn an unsere Zielvariable. var n = require("notification"); bindet notification() an 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());
Attribute deklarieren: n.title und 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()
Deklarieren Sie die Prototyp-Methode: 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);
Jetzt sollte unsere Init()-Methode so aussehen:
// 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()); }
Jetzt müssen Sie nur noch die C++-Methoden schreiben, die wir in der Init-Methode verwenden: New, GetTitle, SetTitle, GetIcon, SetIcon, Send
Konstruktormethode: New()
Die New()-Methode erstellt eine neue Instanz unserer benutzerdefinierten Klasse (ein Gtknotify-Objekt), legt einige Anfangswerte fest und gibt dann den JavaScript-Handler für das Objekt zurück. Dies ist das erwartete Verhalten von JavaScript, das einen Konstruktor mit dem neuen Operator aufruft.
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()
Was folgt, ist größtenteils Boilerplate-Code, der auf die Wertekonvertierung zwischen C++ und JavaScript (v8) hinausläuft.
// 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; }
Prototypmethode: Send()
Zuerst extrahieren wir die Referenz des C++-Objekts und verwenden dann die Eigenschaften des Objekts, um die Benachrichtigung und Anzeige zu erstellen Es.
// 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); }
Erweiterung kompilieren
node-waf ist ein Build-Tool zum Kompilieren von Node-Erweiterungen, die die grundlegende Kapselung von waf darstellen. Der Build-Prozess kann über eine Datei namens wscript konfiguriert werden.
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']
Jetzt können wir mit dem Erstellen beginnen. Führen Sie den folgenden Befehl im Verzeichnis der obersten Ebene aus:
node-waf configure && node-waf build
If Alles Normalerweise erhalten wir die kompilierte Erweiterung unter: ./build/default/gtknotify.node. Versuchen wir es:
$ node > var notif = require('./build/default/gtknotify.node'); > n = new notif.notification(); { icon: 'terminal', title: 'Node.js' } > n.send("Hello World!"); true
Der obige Code zeigt eine Benachrichtigungsmeldung in der oberen rechten Ecke an Bildschirm.
Eingebaut in ein npm-Paket
Das ist sehr cool, aber wie teilen Sie die Ergebnisse Ihrer Bemühungen mit der Node-Community? Dies ist der Hauptzweck von npm : Es ist einfacher zu erweitern und zu verteilen. Das Erstellen von npm-Erweiterungspaketen ist sehr einfach. Sie müssen lediglich eine Datei package.json in Ihrem obersten Verzeichnis erstellen, die Ihre Erweiterungsinformationen enthält:
Weitere Informationen zum package.json-Format finden Sie in der Dokumentation über npm help json.{ // 扩展的名称 (不要在名称中包含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" } }
Sie können dies jetzt in Ihrer obersten Ebene tun Verzeichnis über Führen Sie npm install aus, um Ihr neues npm-Paket zu installieren. Wenn alles gut geht, sollten Sie in der Lage sein, einfach Ihre Erweiterung var notify = require('your package name'); zu laden Sie können einen Link zu Ihrem Entwicklungsverzeichnis erstellen, ohne jedes Mal eine Installation/Deinstallation durchführen zu müssen.
Angenommen, Sie haben eine coole Erweiterung geschrieben. Vielleicht möchten Sie das zentrale npm-Repository zuerst erstellen ein Konto:
Gehen Sie als Nächstes zurück zu Ihrem Stammverzeichnis für die Codierung und führen Sie Folgendes aus:
$ npm adduser
$ npm publish
Das obige ist der detaillierte Inhalt vonZusammenfassung der verschiedenen Codebeispiele für Erweiterungsmethoden von Node.j. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!