Node.js ist eine serverseitige Laufzeitumgebung, um Webanwendungen oder Webservices zu erstellen. Für das Erstellen von interaktiven Webseiten wird clientseitig JavaScript verwendet. Hieraus entstand die Idee, JavaScript auch für Serveranwendungen zu nutzen. Die Laufzeitumgebung ist die V8 Engine von Google. Das bedeutet, dass auf der IBM i die gleiche JavaScript Engine implementiert ist wie in Chrome, dem Browser von Google. Node.js ist seit Dezember 2014 für die IBM i kostenlos verfügbar.

Und so arbeitet die Anwendung: Ein RPG-Programm schreibt Daten für eine SMS in eine DataQueue im JSON-Format, und zwar den Text der SMS, die Telefonnummer des Empfängers und die Telefonnummer des Senders, was dann folgendermaßen aussieht:

{"body": "Hello", "to": "+123456789", "from": "+123456789"}

Ein Node.js-Programm „lauscht“ an der DataQueue, ob neue Daten vorhanden sind. Diese werden dann über die Twilio API als SMS versendet.

Der Versand von SMS-Daten über Twilio ist ein Beispiel. Mittlerweile verfügen allerdings viele SMS-Versender über Node.js APIs, die sehr einfach über den Node Package Manager heruntergeladen werden können. Auf diese Weise können Sie die Anwendung auch leicht auf andere Anbieter übertragen.

1. Systemvoraussetzungen

Hier finden Sie einen Einstieg in Node.js: Einstieg

Um Node.js zu installieren, benötigen Sie mindestens V7R1 und folgende Lizenzprogramme:

5770-SS1 Option 33 Portable App Solutions Environment
5733-SC1 Option 1 OpenSSH, OpenSSL, zlib
5770-DG1 *Base IBM HTTP-Server für i
5733-OPS Option 1 Node.js Runtime

Node.js ist ein kostenfreies Lizenzprogramm, das derzeit in drei Versionen auf der IBM i verfügbar ist:

5733-OPS Option 1 Node.js V0.x
5733-OPS Option 5 Node.js V4.x
5733-OPS Option 10 Node.js V6.x

Nach der Installation befindet sich Node.js in folgenden Verzeichnissen:

V0.x /QopenSys/QIBM/ProdData/Node
V4.x /QopenSys/QIBM/ProdData/OPS/Node4
V6.x /QopenSys/QIBM/ProdData/OPS/Node6

Wenn Sie Node V4 oder V6 nutzen wollen, dann stellen Sie die Version über die Qshell ein:

V4: 5250> qsh
$ /QOpenSys/QIBM/ProdData/OPS/Node4/bin/nodever.sh 4
Node.js v4 will now be used.

V6: 5250> qsh
$ /QOpenSys/QIBM/ProdData/OPS/Node6/bin/nodever.sh 6
Node.js v6 will now be used.

Jetzt können Sie prüfen, welche Version von Node.js und dem Node Package Manager eingestellt ist. Der Node Package Manager ist ein Dienstprogramm, um Open Source Software (derzeit 240.000 Pakete) zu installieren, zu aktualisieren und zu löschen (siehe www.npmjs.com).

5250> qsh
$ node -v
v6.9.1
$ npm -v
3.10.8

Die Twilio API installieren Sie mit dem Node Package Manager:

5250> qsh
$ npm install twilio

Die API befindet sich nach der Installation im Verzeichnis /home/node_modules/twilio. Für die Authentifizierung benötigen Sie eine accountSid und den authToken. Sie erhalten diese nach Ihrer Registrierung unter www.twilio.com/console.

Für das Erzeugen der JSON-Daten ist derzeit das Open-Source-Serviceprogramm YAJL (Yet another JSON Library) von Scott Klement am besten geeignet. Sie können das Programm über folgenden Link kostenlos herunterladen: www.scottklement.com/yajl/

2. Die Komponenten der Anwendung

a) Erstellen der DataQueue mit einen CL-Programm

PGM

CRTDTAQ DTAQ(MYLIB/SNDSMSQ) MAXLEN(5000) SEQ(*FIFO) +
SIZE(*MAX2GB) AUTORCL(*YES) +
TEXT('Dataqueue SMS Senden') AUT(*USE)

ENDPGM

b) RPG-Programm zum Schreiben der Daten in die DataQueue. Die Daten werden im JSON-Format in die DataQueue geschrieben: {„body“: „Hello“, „to“: „+123456789“, „from“: „+123456789“}

Bei diesem Programm handelt es sich um ein „Mainline“-Programm. In den Ctl-Opt wird über Main(main) die Main-Prozedur aufgerufen. Ein *INLR ist nicht mehr notwendig. Weitere Informationen finden Sie unter Mcpressonline.com.

ctl-opt main(main) dftactgrp(*no) alloc(*teraspace) bnddir('YAJL');
//------------------------------------------------------------------//
// //
// Send JSON data to DataQueue //
// //
//----------------- //
// R.Ross 10.2016 * //
//------------------------------------------------------------------//
// Prototypes //
//------------------------------------------------------------------//

/include json/qrpglesrc,yajl_h

//------------------------------------------------------------------//
// Send Data to DTAQ //
//------------------------------------------------------------------//

dcl-pr snddtaq extpgm('QSNDDTAQ');
##dtqname like(d#dtqname) const;
##dtqlib like(d#dtqlib) const;
##dtqlength like(d#dtqlength) const;
##dtqdata char(32766) const options(*varsize);
end-pr;

//------------------------------------------------------------------//
// Variablen für DTQ-API //
//------------------------------------------------------------------//

dcl-s d#dtqname char(10) inz('SNDSMSQ'); // DTQ-Name
dcl-s d#dtqlib char(10) inz('MYLIB'); // DTQ-Lib
dcl-s d#dtqlength packed(05) inz(%size(d#dtqdata)); // DTQ-Length
dcl-s d#dtqwait packed(05) inz(-1); // DTQ-Wait
dcl-s d#dtqdata char(5000); // DTQ-Data

//------------------------------------------------------------------//
// Variablen //
//------------------------------------------------------------------//

dcl-s body varchar(4000); // SMS-Body
dcl-s to varchar(30); // SMS-To
dcl-s from varchar(30); // SMS-From

dcl-s jsondata varchar(5000); // JSON-Data

dcl-s index uns(10); // Index

//------------------------------------------------------------------//
// Main //
//------------------------------------------------------------------//
dcl-proc main;

for index = 1 to 5; // 5 Testdaten schreiben
body = 'Hello Node ' + %char(index);
to = '+4912345678';
from = '+4912345678';

d#dtqdata = crtjson(body:to:from);

snddtaq(d#dtqname:d#dtqlib:d#dtqlength:d#dtqdata);
endfor;

snddtaq(d#dtqname:d#dtqlib:d#dtqlength:crtjson('*end':to:from));

end-proc;
//------------------------------------------------------------------//
// Procedure - create JSON data //
//------------------------------------------------------------------//
dcl-proc crtjson export;
dcl-pi *n like(jsondata); // JSON-Data
##body like(body) const options(*varsize);
##to like(to) const options(*varsize);
##from like(from) const options(*varsize);
end-pi;

dcl-s p#size int(10) inz(%size(jsondata)); // JSON-length
dcl-s p#len int(10); // Data-length
dcl-s p#rc int(10); // ReturnCode
dcl-s p#json_p pointer; // JSON-Pointer
dcl-s p#jsondata like(jsondata); // JSON-Data

dealloc(n) p#json_p; // JSON-Pointer
p#json_p = %alloc(p#size); // Alloc Pointer

yajl_genopen(*off); // *on = pretty Code

yajl_beginobj();
yajl_addchar('body':##body);
yajl_addchar('to' :##to);
yajl_addchar('from':##from);
yajl_endobj();

p#rc = yajl_copybuf(1141:p#json_p:p#size:p#len); // CCSID 1141

if p#rc = *zero and p#len > *zero;
p#jsondata = %str(p#json_p:p#len);
endif;

yajl_genclose();

return p#jsondata;

end-proc;
//------------------------------------------------------------------//

c) Das Node.js-Programm nimmt die Daten aus der DataQueue entgegen, verarbeitet sie und wartet auf einen neuen Eintrag. Hierfür wird die QRCVDTAQ API benutzt. Das Skript befindet sich im IFS:

/QOpenSys/QIBM/ProdData/OPS/Node4/os400/xstoolkit/lib/idataq.js

In diesem Skript ist die Wait-Funktion auf einen neuen Eintrag nicht implementiert. Deshalb zeige ich Ihnen, wie Sie diese Funktion implementieren:
Das Originalskript kopieren und unter dem neuen Namen idataq2.js in das gleiche Verzeichnis einfügen.

Wenn Sie mit Node.js V4 arbeiten, lautet der Pfad:

/QOpenSys/QIBM/ProdData/OPS/Node4/os400/xstoolkit/lib/idataq2.js

Mit Node.js V6 lautet der Pfad:

/QOpenSys/QIBM/ProdData/OPS/Node6/os400/xstoolkit/lib/idataq2.js

Im Skript idataq2.js ändern Sie folgende Statements:
Zeile 70: iDataQueue.prototype.receiveFromDataQueue = function(name, lib, length, wait, cb) {
Zeile 76: pgm.addParam(wait, „5p0“);

d) Das Node.js-Programm sendSMSDataFromQueue.js. Sie erstellen unter dem Verzeichnis /home das Verzeichnis /node und hinterlegen hier das Skript sendSMSDataFromQueue.js.

var xt = require('/QOpenSys/QIBM/ProdData/OPS/Node4/os400/xstoolkit/lib/itoolkit');
var dq = require('/QOpenSys/QIBM/ProdData/OPS/Node4/os400/xstoolkit/lib/idataq2');
var twilio = require('twilio');

var accountSid = 'abcdefghijklmn'; // Account SID von der www.twilio.com/console
var authToken = 'abcdefghijklmn'; // AuthToken von der www.twilio.com/console

var conn = new xt.iConn('*LOCAL', 'User', 'Password'); // User und Password der IBM i
var dtq = new dq.iDataQueue(conn);
var client = new twilio.RestClient(accountSid, authToken);

var data = '';

while (data.body !== '*end') { // Leseschleife auf die DataQueue
data = JSON.parse(dtq.receiveFromDataQueue('SNDSMSQ', 'MYLIB', 5000, -1));
console.log('data: ' + JSON.stringify(data));
sendSMS(data);
}

function sendSMS(data) {
client.messages.create({
body: data.body, // SMS body
to: data.to, // SMS to number
from: data.from // SMS from a valid Twilio number
}, function(err, message) {
if (err) {
console.error(err.message);
}
});
}

e) Start des Node.js-Programms sendSMSDataFromQueue.js in der Qshell

5250> qsh
node /home/node/sendSMSDataFromQueue.js

f) Aufruf des RPG-Programms mit Call. Das Programm schreibt nun fünf Test-SMS in die DataQueue. Das Node.js-Programm sendSMSDataFromQueue.js liest die Daten aus der Queue, protokolliert sie mit dem Befehl console.log und sendet sie an Twilio. Twilio versendet dann die SMS an den Empfänger.

Dieses Projekt finden Sie unter https://github.com/RainerRoss/Send-SMS-with-Twilio-from-IBM-i.

Viel Spaß beim Ausprobieren.