Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Node.js

Пишем аддоны для Node.js

by
Difficulty:IntermediateLength:MediumLanguages:

Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)

Node.js отлично подходит для написания вашего back-end в JavaScript. Но что, если вам нужна некоторая функциональность, которая не предоставляется из коробки, или которая также не может быть выполнена даже с использованием модулей, но доступна в виде библиотеки C / C ++? Ну, вы можете написать аддон, который позволит вам использовать эту библиотеку в вашем JavaScript-коде. Посмотрим, как.

Как вы можете прочитать в документации Node.js, аддоны представляют собой динамически связанные общие объекты, которые могут обеспечить связь для библиотек C/C++. Это означает, что вы можете использовать практически любую библиотеку C/C ++ и создать аддон, который позволит вам использовать его в Node.js.

В качестве примера мы создадим оболочку для стандартного объекта std::string.


Подготовка

Прежде чем мы начнем писать код, вы должны убедиться, что у вас есть все необходимое для компиляции модуля. Вам нужен node-gyp и все его зависимости. Вы можете установить node-gyp, используя следующую команду:

Что касается зависимостей, то в системах Unix вам понадобятся:

  • Python (2.7, 3.x не будет работать)
  • make
  • C ++ компилятор toolchain (например, gpp или g ++)

Например, на Ubuntu вы можете установить все это с помощью этой команды (Python 2.7 уже должен быть установлен):

В Windows вам понадобятся:

  • Python (2.7.3, 3.x не работает)
  • Microsoft Visual Studio C ++ 2010 (для Windows XP / Vista)
  • Microsoft Visual Studio C ++ 2012 для Windows Desktop (Windows 7/8)

Express версия Visual Studio отлично работает.


Файл binding.gyp

Этот файл используется node-gyp для создания соответствующих файлов сборки для вашего аддона. Вся документация файла .gyp может быть найдена на их странице Wiki, но для наших целей этот простой файл будет делать:

target_name может быть любым именем, которое вам нравится. Массив sources содержит все исходные файлы, которые использует аддон. В нашем примере есть addon.cc, который будет содержать код, необходимый для компиляции нашего аддона и stdstring.cc, который будет содержать наш класс-оболочку.


Класс STDStringWrapper

Начнем с определения нашего класса в файле stdstring.h. Первые две строки должны быть вам знакомы, если вы когда-либо программировали на C ++.

Это стандарт include guard. Затем мы должны подключить эти два заголовка:

Первый - для класса std::string, а второй - для всех вещей, связанных с Node и V8.

После этого мы можем объявить наш класс:

Для всех классов, которые мы хотим включить в наш аддон, мы должны расширить класс node::ObjectWrap.

Теперь мы можем начать определять private свойства нашего класса:

Помимо конструктора и деструктора, мы также определяем указатель на std::string. Это ядро метода, который можно использовать для склеивания библиотек C/C ++ в Node - мы определяем приватный указатель на класс C/C++, а затем используем этот указатель во всех методах.

Затем мы объявляем статическое свойство constructor, которое будет содержать функцию для создания нашего класса в V8:

Для получения дополнительной информации о шаблоне v8::Persistent обратитесь к документации.

Теперь у нас также будет метод New, который будет назначен constructor выше, когда V8 инициализирует наш класс:

Каждая функция для V8 будет выглядеть так: она примет ссылку на объект v8 :: Arguments и вернет v8 :: Handle> v8 :: Value> - вот как V8 имеет дело со слабо типизированным JavaScript, когда мы программируем в сильном -тип C ++.

После этого у нас будет два метода, которые будут вставлены в прототип нашего объекта:

Метод toString() позволит нам получить значение s_ вместо [Object object], когда мы будем использовать его с обычными строками JavaScript.

Наконец, у нас будет метод инициализации (он будет вызываться V8 для назначения функции constructor), и мы можем закрыть include guard:

Объект exports эквивалентен module.export.


Файл stdstring.cc, конструктор и деструктор

Теперь создайте файл stdstring.cc. Сначала мы должны включить наш заголовок:

И определите свойство constructor (поскольку оно статично):

Конструктор для нашего класса просто выделит свойство s_:

А деструктор delete его, чтобы избежать утечки памяти:

Кроме того, вы должны delete все, что вы создаете с помощью new, каждый раз, когда есть вероятность, что будет выброшено исключение, помните об этом или используйте общие указатели.


Метод Init

Этот метод будет вызываться V8 для инициализации нашего класса (определение constructor, поместите все, что мы хотим использовать в JavaScript в объекте exports):

Сначала мы должны создать шаблон функции для нашего метода New:

Это похоже на new Function в JavaScript - позволяет нам подготовить наш класс JavaScript.

Теперь мы можем установить имя этой функции, если хотим (если вы опустите это, ваш конструктор будет анонимным, он будет иметь функцию someName () {} вместо function () {}):

Мы использовали v8::String::NewSymbol(), который создает специальный тип строки, используемой для имен свойств - это немного экономит время на работу.

После этого мы задаем, сколько полей будет иметь каждый экземпляр нашего класса:

У нас есть два метода - add() и toString(), поэтому мы устанавливаем значение в 2.

Теперь мы можем добавить наши методы к прототипу функции:

Много кода, но при внимательном рассмотрении вы увидите шаблон: мы используем tpl->PrototypeTemplate()->Set(), чтобы добавить каждый из методов. Мы также даем каждому из них имя (используя v8::String::NewSymbol()) и FunctionTemplate.

Наконец, мы можем поместить конструктор в свойство constructor нашего класса и в объект exports:


Метод New

Теперь мы определим метод, который будет действовать как объект JavaScript Object.prototype.constructor:

Сначала мы должны создать для этого область:

После этого мы можем использовать метод .IsConstructCall() объекта args, чтобы проверить, была ли вызвана функция-конструктор с использованием ключевого слова new:

Если это так, давайте сначала преобразуем аргумент, переданный в std::string следующим образом:

... так что мы можем передать его конструктору нашего класса-оболочки:

После этого мы можем использовать метод .Wrap() объекта, который мы создали (который унаследован от node::ObjectWrap), чтобы присвоить его переменной this:

Наконец, мы можем вернуть вновь созданный объект:

Если функция не была вызвана с помощью new, мы просто вызовет конструктор. Затем создадим константу для аргумента count:

Теперь давайте создадим массив с нашим аргументом:

И передайте результат метода constructor->NewInstance в scope.Close, так что объект может быть использован позже (scope.Close в основном позволяет вам сохранить дескриптор объекта, переместив его в более высокую область действия - вот как работают функции ):


Метод add

Теперь давайте создадим метод add, который позволит вам добавить что-то во внутреннюю std::string нашего объекта:

Сначала мы должны создать область для нашей функции и преобразовать аргумент в std::string, как это было раньше:

Теперь нам нужно развернуть объект. Это обратная сторона обертывания, которую мы сделали ранее - на этот раз мы получим указатель на наш объект из переменной this:

Затем мы можем получить доступ к свойству s_ и использовать его метод .append():

Наконец, мы возвращаем текущее значение свойства s_ (опять же, используя scope.Close):

Поскольку метод v8::String::New() принимает только char pointer в качестве значения, мы должны использовать obj->s_->c_str() для его получения.


Метод toString

Последний необходимый метод позволит нам преобразовать объект в JavaScript String:

Это похоже на предыдущий метод, мы должны создать область действия:

Разверните объект:

И верните свойство s_ как v8::String:


Сборка

Последнее, что нужно сделать, прежде чем мы будем использовать наш аддон, конечно же, является компиляцией и сборкой. Это будет включать только две команды. Первая:

Это создаст соответствующую конфигурацию сборки для вашей ОС и процессора (Makefile в UNIX и vcxproj в Windows). Чтобы скомпилировать и связать библиотеку, просто вызовите:

Если все пойдет хорошо, вы должны увидеть что-то подобное в консоли:

И должен быть создан каталог build, созданный в папке вашего аддона.

Тестирование

Теперь мы можем протестировать наш аддон. Создайте файл test.js в папке вашего аддона и подключите скомпилированную библиотеку (вы можете опустить расширение .node):

Затем создайте новый экземпляр нашего объекта:

И сделайте что-нибудь с ним, например, добавив или преобразова его в строку:

Это приведет к следующему примеру консоли:

Вывод

Надеюсь, что после прочтения этого урока вы больше не будете думать, что создавать, собирать и тестировать собственные библиотеки на базе C/C ++, Node.js сложно. Используя эту технику, вы можете легко переносить практически любую библиотеку C/C++ в Node.js. Если вы хотите, вы можете добавить дополнительные функции в аддон, который мы создали. Существует множество методов в std::string, с которыми вы можете попрактиковаться.


Полезные ссылки

Ознакомьтесь со следующими ресурсами для получения дополнительной информации о Node.js addon development, V8 и библиотеке циклов событий C.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.