От ASP.Net к Node.JS: как мы переписали серверную часть редакторов ONLYOFFICE

К релизу нового корпоративного решения ONLYOFFICE Enterprise Edition мы переписали код серверной части наших онлайн-редакторов на Node.JS и теперь, собственно, хотим поделиться опытом освобождения от ASP.Net, в ловушке которого мы оказались еще пять лет назад.

Переход на Node.JS стал логичным продолжением развития облачного офиса на Linux. Первая версия для него появилась почти год назад — тогда мы приняли решение использовать проект Mono. О проблемах, возникших при портировании на Mono системы для совместной работы, мы уже рассказывали. На тот момент работа над редакторами для Linux’а только начиналась. Сначала вышла бета-версия ONLYOFFICE Document Server, также написанная с использованием Mono. Сейчас она доступна в open source версии 3.0.

В новое серверное решение ONLYOFFICE Enterprise Edition мы включили обновленные редакторы ONLYOFFICE Document Editors 3.5, уже на Node.JS. Почему, как и что получилось расскажем далее.

image
Мотивы ухода от Mono

1. Снижение числа багов

Использование чужого продукта, пусть и хорошего (сейчас мы говорим о Mono), чревато размножением багов в геометрической прогрессии. Мы запускаем свой код, условно говоря, в «чёрный ящик», в котором с ним происходит почти всё что угодно. Число наших багов умножается на число багов чужого продукта и, как результат, начинается бесконечная борьба за стабильность, которую часто приходится начинать заново с выходом очередных (и внеочередных) обновлений.

2. Кроссплатформенность

Нам был нужен кроссплатформенный код для десктопных редакторов, работающих на всех ОС, в том числе и на мобильных. Совсем недавно вышло приложение ONLYOFFICE Documents для iOS с возможностью редактирования текстов и просмотра таблиц, pdf-файлов и презентаций. Останавливаться на этом мы не планируем, однако о планах позднее.

В общем и целом, мы осознали, что ASP.Net и Mono перестали отвечать нашим потребностям, и задались вопросом: на чем писать дальше?

Почему Node.JS?

Рассмотрев несколько вариантов (среди которых Ruby, Java, Python, Node.JS), мы выбрали последний. Причины выбора достаточно очевидны: у нас уже был неплохой опыт работы с этой платформой — на Node.JS написаны серверные части редакторов: службы совместного редактирования (CoAuthoring) и проверки орфографии (SpellChecker).

В процессе работы мы старались заложить в архитектуру возможности более устойчивой работы, масштабирования и кластеризации. Кроме того, пришлось столкнуться с некоторыми трудностями, связанными с особенностями Node.JS. Об этом расскажем подробнее.

Сложности при переходе на Node.JS

1. Проблема с битовыми операциями

Что было: В JavaScript перед битовыми операциями число преобразуется в 32-bit signed int

Например, у нас был C# код:

var byteCount = Math.Min(5, data.Length - i);

ulong buffer = 0;

for (var j = 0; j < byteCount; ++j)

{

        buffer = (buffer << 8) | data[i + j];

}

Проблема: В Node.JS после цикла переменная buffer становится 2^40 и содержит некорректное число.

Решение в Node.JS: Чтобы избежать «превращений», мы переписали подобные места без битовых операций

buffer = (buffer * 256) + data[i + j];

2. Проблема со скачиванием файла

Что было: Файлы скачиваются по ссылке при конвертации документов. На C# для скачивания использовался класс System.Net.HttpWebRequest.

Проблема: В Node.JS есть два стандартных модуля для веб-запросов — http и https. Интерфейсы модулей абсолютно одинаковы, и разработчику необходимо вручную выбирать, какой модуль использовать в каждом конкретном случае. При этом стандартные модули не поддерживают автоматический переход по адресу, указанному в заголовке переадресации, если сервер вернул статус 301 или 302.

Решение в Node.JS: Мы использовали дополнительный модуль, который оборачивает стандартные модули и автоматически решает проблему с выбором между http и https и редиректами. В Node.JS есть несколько подобных модулей — из них наш выбор пал на «request».

3. Проблема с обработкой запросов

Что было: В C# для обработки запросов мы создавали класс-наследник от IHttpAsyncHandler или IHttpHandler. Таким образом, вся обработка запросов была «из коробки».

Проблема: В Node.JS нет встроенных модулей для обработки запросов, поэтому её пришлось собирать «под себя».

Решение в Node.JS: Для обработки запросов в Node.JS мы используем модуль «express», а чтобы иметь доступ к телу POST запроса — модуль «body-parser».

Для обработки POST c multipart/form-data мы выбирали из множества модулей с похожей функциональностью. Возможные варианты (multiparty, busboy, formidable) отличаются интерфейсом, настройками, возможностью отключить запись временного файл в temp и поддержкой потоков. Мы выбрали «multiparty» — с его помощью можно напрямую записывать данные как поток в хранилище Amazon S3.

4. Проблема с особенностями языка и стандартных библиотек

Что было: Одним из главных плюсов C# является большая стандартная библиотека и разнообразный синтаксис.

Например, в C# можно передать параметр в функцию по ссылке (ref)

private int CreateIndexByOctetAndMovePosition(ref string data, int currentPosition, ref int[] index)

Проблема: Если переписать эту функцию на JavaScript «в лоб», то строка, переданная в качестве аргумента, будет скопирована. При работе с большими строками это приведет к лишней трате процессорного времени на их копирование и увеличению потребления памяти.

Решение в Node.JS: Чтобы предотвратить копирование больших строк при передаче в функцию, пришлось либо переводить их в бинарный формат (Buffer), либо оборачивать в объект и передавать его.

Кроме того, в Node.JS отсутствуют «из коробки» функции для удаления непустых директорий, создания директорий без родительских поддиректорий, работа с xml и т.д. Их пришлось дописывать руками.

Результаты и планы

Мы получили новый сервер, не использующий ASP.Net, способный выдерживать большие нагрузки. Плюсы для конечного пользователя: он не падает и не висит. Плюсы для нас как разработчиков: он не падает и не висит.

Но, естественно, всё затевалось не только ради серверов на Node.JS — нам нужен был кроссплатформенный код, и мы его получили. Теперь наши редакторы смогут работать на любых ОС.

Сейчас готовятся к выпуску наши десктопные редакторы под Windows, MacOS и Linux (да, работа в браузерах также связана с некоторыми ограничениями, которые мы хотим преодолеть). Кроме того, мы продолжаем улучшать наши онлайн-редакторы. Например, совсем скоро ONLYOFFICE Documents для iOS, о котором мы писали выше, появятся редактор таблиц (сейчас в стадии тестирования) и редактор презентаций (там же). Редакторы под Android выйдут в 2016 году.

© Habrahabr.ru