[Перевод] Вызываем код на Java, C, NodeJS, C#, Python из InterSystems IRIS

Одно из ключевых направлений развития платформы данных InterSystems IRIS — открытость. Открытость во взаимодействии с языками программирования, технологиями и протоколами. Поддержка языков программирования двусторонняя — возможен как вызов кода из InterSystems IRIS, так и предоставляется API для работы с InterSystems IRIS извне. В этой статье речь пойдёт о первом варианте — вызове кода из InterSystems IRIS. Целью этого небольшого повествования является демонстрация того, как просто и удобно можно это сделать. Я не буду сравнивать различные языки программирования (хотя в конце есть таблица по скорости работы различных имплементаций), всё зависит от решаемых вами задач и требований, предъявляемых к результату разработки. В этой статье я продемонстрирую несколько различных подходов к вызовам сторонних библиотек, а реализовывать мы будем одну и ту же функциональность — вызов функции DELFATE из библиотеки zlib.

Недавно я прочитал вот эту статью. Речь там идет как раз о вызове функции DELFATE на NodeJS из платформы InterSystems IRIS, и эта статья натолкнула меня на мысль описать вызов кода и на других языках.
Итак, начнем с NodeJS. Я беру код почти целиком из статьи Бернда, за исключением того, что в нем не используются файлы, а прямое http-соединение для передачи данных. В целом лучше передавать данные в теле запроса, и кодировать как запрос, так и ответ в виде base64. Тем не менее, вот код:

//zlibserver.js
const express = require('express');
const zlib = require('zlib');

var app = express();

 app.get('/zlibapi/:text', function(req, res) {
    res.type('application/json');

    var text=req.params.text;

    try {        
        zlib.deflate(text, (err, buffer) => {
           if (!err) {
                res.status(200).send(buffer.toString('binary'));
            } else {
                res.status(500).json( { "error" : err.message});
            // handle error
            }
        });
     }
    catch(err) {
      res.status(500).json({ "error" : err.message});
      return;
    }

});
app.listen(3000, function(){
    console.log("zlibserver started");
});

Чтобы запустить сервер, выполните в терминале ОС (должны быть установлены node и npm):

cd <repo>node
npm install
node  ./zlibserver.js

Что здесь происходит? Слушаем порт 3000, сжимаем DEFLATE тело запроса и возвращаем сжатые данные в ответ. На стороне InterSystems IRIS используется http запрос для взаимодействия с данным API:

/// NodeJS implementation
/// do ##class(isc.zlib.Test).node()
ClassMethod node(text As %String = "Hello World", Output response As %String) As %Status
{
    kill response
    set req = ##class(%Net.HttpRequest).%New()
    set req.Server = "localhost"
    set req.Port = 3000
    set req.Location = "/zlibapi/" _ text
    set sc = req.Get(,,$$$NO)
    quit:$$$ISERR(sc) sc
    set response = req.HttpResponse.Data.Read($$$MaxStringLength)
    quit sc
}

Обратите внимание, что я устанавливаю третий аргумент set sc = req.Get(,,$$$NO)reset равным нулю. Если вы пишете интерфейс для внешнего http(s) сервера, то лучше всего повторно использовать один объект запроса и просто модифицировать его по мере необходимости для выполнения новых запросов.

Java Gateway позволяет вызывать произвольный Java-код. Недавно я писал про него более подробно. Стандартная библиотека Java включает класс Deflater, который делает именно то, что нам нужно:

package isc.zlib;

import java.util.Arrays;
import java.util.zip.Deflater;

public abstract class Java {

    public static byte[] compress(String inputString) {
        byte[] output = new byte[inputString.length()*3];
        try {
            // Encode a String into bytes
            byte[] input = inputString.getBytes("UTF-8");

            // Compress the bytes

            Deflater compresser = new Deflater();
            compresser.setInput(input);
            compresser.finish();
            int compressedDataLength = compresser.deflate(output);
            compresser.end();
            output = Arrays.copyOfRange(output, 0, compressedDataLength);

        } catch (java.io.UnsupportedEncodingException ex) {
            // handle
        }

        return output;
    }
}

Особенность этой имплементации заключается в том, что она возвращает массив byte[], который становится потоком на стороне InterSystems IRIS. Я пытался вернуть строку, но не смог найти, как сформировать бинарную строку из byte[]. Если у вас есть какие-то идеи, пожалуйста, оставьте комментарий.
Чтобы запустить код, поместите jar из релизов в папку <instance>/bin, загрузите код в свой инстанс InterSystems IRIS и выполните:

write $System.Status.GetErrorText(##class(isc.zlib.Utils).createGateway())
write $System.Status.GetErrorText(##class(isc.zlib.Utils).updateJar())

Проверьте метод createGateway перед запуском. Второй аргумент javaHome предполагает что переменная окружения JAVA_HOME установлена. Если это не так, вручную передайте путь до Java 1.8 JRE. Для сжатия строки text выполните этот код:

set gateway = ##class(isc.zlib.Utils).connect()
set response = ##class(isc.zlib.Java).compress(gateway, text)

Библиотека InterSystems Callout это динамическая библиотека, предоставляющая функции, которые вы можете вызвать из InterSystems IRIS.

Вот наша библиотека:

#define ZF_DLL

// Ugly Windows hack
#ifndef ulong
   typedef unsigned long ulong;
#endif

#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "zlib.h"
#include <cdzf.h>

int Compress(char* istream, CACHE_EXSTRP retval)
{
    ulong srcLen = strlen(istream)+1;      // +1 for the trailing ``
    ulong destLen = compressBound(srcLen); //  estimate size needed for the buffer
    char* ostream = malloc(destLen);
    int res = compress(ostream, &destLen, istream, srcLen);
    CACHEEXSTRKILL(retval);
    if (!CACHEEXSTRNEW(retval,destLen)) {return ZF_FAILURE;}
    memcpy(retval->str.ch,ostream,destLen);   // copy to retval->str.ch
    return ZF_SUCCESS;
}

ZFBEGIN
    ZFENTRY("Compress","cJ",Compress)
ZFEND

Для запуска загрузите dll или so со страницы релизов в папку <instance>/bin. В репозитории есть также скрипты для сборки вашей собственной версии библиотеки.

Перед сборкой установите:

  • Linux: apt install build-essential zlib1g zlib1g-devel
  • Windows: WinBuilds

Для работы с Callout библиотекой выполните:

set path =  ##class(isc.zlib.Test).getLibPath() //get path to library file
set response = $ZF(-3, path, "Compress", text)       // execute function
do $ZF(-3, "")                                  //unload library

Используя Python Gateway вызовем данный код:

import zlib
zlib.compress(b'text')

Из InterSystems IRIS: set out = ##class(isc.py.Callout).SimpleString("import zlib" _ $$$NL _ "x = zlib.compress(b'" _ text _ "')", "x")

Net Gateway позволяет вызывать произвольный код на языке C#. Недавно я писал про него более подробно.
Реализация на C# также возвращает поток, а не строку:

using System;
using System.IO;
using System.IO.Compression;

namespace isc.zlib
{
    public class Net
    {
        public static byte[] compress(String str)
        {
            using (MemoryStream output = new MemoryStream())
            {
                using (DeflateStream gzip = new DeflateStream(output, CompressionMode.Compress))
                {
                    using (StreamWriter writer = new StreamWriter(gzip, System.Text.Encoding.UTF8))
                    {
                        writer.Write(str);
                    }
                }

                return output.ToArray();
            }
        }
    }
}

Для запуска загрузите zlibnet.dll со страницы релизов в папку <instance>/bin.

write $System.Status.GetErrorText(##class(isc.zlib.Utils).createNetGateway())
write $System.Status.GetErrorText(##class(isc.zlib.Utils).updateNet())

Для сжатия строки text выполните этот код:

set gateway = ##class(isc.zlib.Utils).connect()
set response = ##class(isc.zlib.Net).compress(gateway, text)

Несколько неожиданно в статье о механизмах вызова кода на других языках, но в ObjectScript также есть встроенная функция Compress (и парная функция Decompress). Вызывается так: set response = $extract($SYSTEM.Util.Compress(text), 2, *-1)

Помните, что поиск в документации или вопрос на Developers Community может сэкономить вам некоторое время.

Я запустил простой тест (1Kb text, 1 000 000 итераций) на Linux (VPS) и Windows (Ноутбук) и получил следующие результаты.

Windows:

Linux:

Для запуска тестов загрузите код и вызовите: do ##class(isc.zlib.Test).test(textLength, iterations)

С платформой InterSystems IRIS вы легко можете использовать существующий код на ряде популярных языков. Однако выбор реализации не всегда прост: необходимо учитывать несколько метрик, таких как скорость разработки, производительность, кроссплатформенность и простота сопровождения. Ответы на эти вопросы помогут вам определиться с оптимальным планом разработки.

Let’s block ads! (Why?)

Read More

Recent Posts

Роскомнадзор рекомендовал хостинг-провайдерам ограничить сбор данных с сайтов для иностранных ботов

Центр управления связью общего пользования (ЦМУ ССОП) Роскомнадзора рекомендовал компаниям из реестра провайдеров ограничить доступ поисковых ботов к информации на российских сайтах.…

14 часов ago

Apple возобновила переговоры с OpenAI и Google для интеграции ИИ в iPhone

Apple возобновила переговоры с OpenAI о возможности внедрения ИИ-технологий в iOS 18, на основе данной операционной системы будут работать новые…

5 дней ago

Российская «дочка» Google подготовила 23 иска к крупнейшим игрокам рекламного рынка

Конкурсный управляющий российской «дочки» Google подготовил 23 иска к участникам рекламного рынка. Общая сумма исков составляет 16 млрд рублей –…

6 дней ago

Google завершил обновление основного алгоритма March 2024 Core Update

Google завершил обновление основного алгоритма March 2024 Core Update. Раскатка обновлений была завершена 19 апреля, но сообщил об этом поисковик…

6 дней ago

Нейросети будут писать тексты объявления за продавцов на Авито

У частных продавцов на Авито появилась возможность составлять текст объявлений с помощью нейросети. Новый функционал доступен в категории «Обувь, одежда,…

6 дней ago

Объявлены победители международной премии Workspace Digital Awards-2024

24 апреля 2024 года в Москве состоялась церемония вручения наград международного конкурса Workspace Digital Awards. В этом году участниками стали…

6 дней ago