node.js XML-RPC Server

Das Pendant zum XML-RPC Client,
der XML-RPC Server. Dieser nimmt in diesem Beispiel auf Port 1337 ab und verarbeitet die eingehenden Anfragen, wertet diese aus und sendet eine Antwort zurück.

 

Beispiel Script

/* Das Modul laden */
var fs = require('fs')
  , xmlrpc = require('./xmlrpc/lib/node-xmlrpc.js')

/*
XML-RPC Server
*/

/*
Die verschiedenen Inhalte der Anfragen werden in verschiedenden Objekte hinterlegt.
*/
var serverContents = {
  calls: []
, arrayValue: null
, booleanValue: null
, dateTimeValue: null
, doubleValue: null
, integerValue: null
, stringValue: null
, structValue: null
}

// XML-RPC Server erstellen
var serverOptions = {
  host: 'localhost'
, port: 1337
}
// Hierbei kann man wie beim Client auch einen String fuer den Connect uebergeben.
// var serverOptions = 'http://localhost:9090'
var server = xmlrpc.createServer(serverOptions)

// Einen HTTPS XML-RPC Server starten
/*
var secureServerOptions = {
host: 'localhost'
, port: 443
, key: fs.readFileSync('./test-key.pem')
, cert: fs.readFileSync('./test-cert.pem')
}
var server = xmlrpc.createSecureServer(secureServerOptions)
*/

// Methoden fuer die verschiedenen Anfragen
// Arrays
// 'setArray' is the method call to listen for
server.on('setArray', function (err, params, callback) {
  serverContents.calls.push('setArray')
  serverContents.arrayValue = params[0]
  callback()
})
server.on('getArray', function (err, params, callback) {
  serverContents.calls.push('getArray')
  callback(null, serverContents.arrayValue)
})
// Boolesche Werte
server.on('setBoolean', function (err, params, callback) {
  serverContents.calls.push('setBoolean')
  serverContents.booleanValue = params[0]
  callback()
})
server.on('getBoolean', function (err, params, callback) {
  serverContents.calls.push('getBoolean')
  callback(null, serverContents.booleanValue)
})
// Datumswerte
server.on('setDate', function (err, params, callback) {
  serverContents.calls.push('setDate')
  serverContents.dateValue = params[0]
  callback()
})
server.on('getDate', function (err, params, callback) {
  serverContents.calls.push('getDate')
  callback(null, serverContents.dateValue)
})
// Werte vom Typ Double
server.on('setDouble', function (err, params, callback) {
  serverContents.calls.push('setDouble')
  serverContents.doubleValue = params[0]
  callback()
})
server.on('getDouble', function (err, params, callback) {
  serverContents.calls.push('getDouble')
  callback(null, serverContents.doubleValue)
})
// Integer Werte
server.on('setInteger', function (err, params, callback) {
  serverContents.calls.push('setInteger')
  serverContents.integerValue = params[0]
  callback()
})
server.on('getInteger', function (err, params, callback) {
  serverContents.calls.push('getInteger')
  callback(null, serverContents.integerValue)
})
// String Werte
server.on('setString', function (err, params, callback) {
  serverContents.calls.push('setString')
  serverContents.stringValue = params[0]
  callback()
})
server.on('getString', function (err, params, callback) {
  serverContents.calls.push('getString')
  callback(null, serverContents.stringValue)
})
// Strukturen/Objekte
server.on('setStruct', function (err, params, callback) {
  serverContents.calls.push('setStruct')
  serverContents.structValue = params[0]
  callback()
})
server.on('getStruct', function (err, params, callback) {
  serverContents.calls.push('getStruct')
  callback(null, serverContents.structValue)
})
// Return a fault message
server.on('fakeFault', function (error, params, callback) {
  serverContents.calls.push('fakeFault')
  callback({ faultCode: 2, faultString: 'Uh oh.'}, null)
})

node.js XML-RPC Client

Da ich momentan eine Lösung gesucht habe um aus node.js eine XML-RPC Konforme Nachricht zu senden, stiess ich auf folgenden Ansatz.
Das Script für den XML-RPC Server ist hier zu finden.

 

Zuerst wird das modul “xmlrpc” benötigt. Dieses laden wir mit dem NPM Paketmanager nach.

npm install xmlrpc

Das benötigte Modul findet man nun unter

xmlrpc/lib/

Beispiel Script

/*
XML-RPC CLient
*/
/* Modul laden */
var fs = require('fs')
  , xmlrpc = require('./xmlrpc/lib/node-xmlrpc.js')

 // XML-RPC Client Optionen festlegen
  var clientOptions = {
    host: 'localhost'
  , port: 1337
  , path: '/'
  }
  // Man kann die Optionen auch als String uebergeben
  // var clientOptions = 'http://localhost:1337'
  var client = xmlrpc.createClient(clientOptions)

// HTTPS kann folgendermassen verwendet werden
/*
var secureClientOptions = {
host: 'localhost'
, port: 443
, path: '/'
}
var client = xmlrpc.createSecureClient(secureClientOptions)
*/

  client.methodCall('setArray', [['value1', 'value2']], function(error, value) {
    client.methodCall('getArray', null, function (error, value) {
      console.log('Get Array Response: ' + value)
    })
  })

/*
Verschiedene Beispiel Methoden
*/

// Einen Booleschen Wert senden
 client.methodCall('setBoolean', [true], function (error, value) {
    client.methodCall('getBoolean', null, function (error, value) {
      console.log('Get Boolean Response: ' + value)
    })
  })

// Ein Datumswert senden
  client.methodCall('setDate', [new Date(2016, 05, 08, 11, 35, 10)], function (error, value) {
    client.methodCall('getDate', null, function (error, value) {
      console.log('Get Date Response: ' + value)
    })
  })

  client.methodCall('setDouble', [24.99], function (error, value) {
    client.methodCall('getDouble', null, function (error, value) {
      console.log('Get Double Response: ' + value)
    })
  })

// Einen Integer Zahlenwert senden
  client.methodCall('setInteger', [23], function (error, value) {
    client.methodCall('getInteger', null, function (error, value) {
      console.log('Get Integer Response: ' + value)
    })
  })

// Einen String senden
  client.methodCall('setString', ['testString1'], function (error, value) {
    client.methodCall('getString', null, function (error, value) {
      console.log('Get String Response: ' + value)
    })
  })

// Mehrere Werte als Object definieren
  client.methodCall('setStruct', [{ nameOfValue: 'Go 1998!' }], function (error, value) {
    client.methodCall('getStruct', null, function (error, value) {
      console.log('Get Struct Response (on next line): ')
      console.log(value)
    })
  })

// Einen null Wert senden
 client.methodCall('fakeFault', null, function (error, value) {
    console.log('Fake Fault Response as Error (on next line): ')
    console.log(error)
  })

node.js TCP/IP Socket Server + MySQL Datenbank

Nachdem im vorherigen Blogpost node.js modul db-mysql Installation das Modul db-mysql installiert wurde. Benutzen wir dieses Modul nun in dem Beispiel Code.

 

 

 

In diesem Beispiel wird ein TCP/IP Socket Server erstellt, der auf Port 8000 lauscht. Dieser kann eine MySQL Datenbank Verbindung aufbauen und Daten in der Datenbank eintragen. Alle Eingaben die vom User mit Enter bestätigt werden, speichert dieser Server in der Datenbank.

MySql Tabellenstruktur:

Tabellenname: test
id, nachricht

Um auf das Modul “db-mysql.js” zuzugreifen, kopieren wir dieses und die erforderlichen kompilierten node Datenbanktreiber aus dem vorherigen Blogpost in unser Script Verzeichniss.

cp -R DB-MYSQL-VERZEICHNISS/node_modules/db-mysql/build /SCRIPTVERZEICHNISS
cp DB-MYSQL-VERZEICHNISS/node_modules/db-mysql/db-mysql.js /SCRIPTVERZEICHNISS

Nun erstellt man wie gehabt eine Textdatei.

vim socket-server-mysql.js

Für dieses Beispiel benötigt man zwei node.js module

var net = require('net');
var mysql = require('./db-mysql.js');

Die Funktion um einen neuen Datanbankeintrag zu erzeugen erstellen wir zu oberst. Wenn die Funktion später aufgerufen wird. Speichert diese den Wert von “name” in der Datenbank.

function insert_data(nachricht){
new mysql.Database({ // Neue mysql Datenbankverbindung aufbauen
    hostname: 'localhost',
    user: 'DBUSER', // Datenbank Benutzername
    password: 'DBPASS', // Datenbank Passwort
    database: 'DBNAME' // Datenbankname
}).connect(function(error) {
    if (error) {
        return console.log('CONNECTION error: ' + error);
    }
    this.query(). // mySQL Query erstellen
        insert('test', // Tabelle 'test'
            ['nachricht'],  // Tabellenspalte 'nachricht'
            [nachricht]
        ).
        execute(function(error, result) { // mySql Query ausführen
                if (error) {
                        console.log('ERROR: ' + error);
                        return;
                }
                console.log('Inserted id: ' + result.id);
        });
});
}

Nun wird nur noch der Codeteil für den TCP/IP Socket benötigt. Sobald der User eine Nachricht an den Server schickt und diese mit EINGABE bestätigt, wird die gesendete Nachricht in die Datenbank geschrieben. Hierbei ist noch zu beachten das der “Carriage return” mit “\n\r” erkannt wird!

var server = net.createServer(function(socket){

        var sock_adr = socket.address();

        socket.write('Welcome on our Server. Port: ' + sock_adr.port);
        console.log('Socket open at' + sock_adr.port + '\n');

        var ausgabe = "";

        socket.on('data', function(data){ /* Ankommende Daten verarbeiten */

                socket.setEncoding("utf8"); /*Encoding ausgabe auf utf8 setzen*/
                ausgabe += data;
                        if(data == "\r\n"){ /*Wenn ENTER Usereingabe in DB schreiben! Carriage Return \r\n !!!*/
                              console.log(ausgabe);
                              insert_data(ausgabe); // Nachricht in Datenbank schreiben.
                              ausgabe = "";
                        }
        });
});

server.listen(8000,"0.0.0.0");

Nun wird der Server gestartet

node socket-server-mysql.js

Um eine Verbindung mit dem Server herzustellen habe ich vorzugsweise Telnet benutzt.

telnet SERVERADRESSE 8000

Ist man verbunden sollte der Server als erstes mit folgender Nachricht antworten

Welcome on our Server. Port: 8000

Tippt man nun etwas ein und bestätigt die Eingabe mit ENTER. Wir die Nachricht in der Datenbank gespeichert.
Leereingaben werden nicht abgefangen und landen auch direkt in der Datenbank. Dies könnte man noch vervollständigen.

Komplettes script:

var net = require('net'); // TCP/IP Networking Modul
var mysql = require('./db-mysql.js'); // mySQL Modul

function insert_data(nachricht){
new mysql.Database({ // Neue mysql Datenbankverbindung aufbauen
    hostname: 'localhost',
    user: 'DBUSER', // Datenbank Benutzername
    password: 'DBPASS', // Datenbank Passwort
    database: 'DBNAME' // Datenbankname
}).connect(function(error) {
    if (error) {
        return console.log('CONNECTION error: ' + error);
    }
    this.query(). // mySQL Query erstellen
        insert('test', // Tabelle 'test'
            ['nachricht'],  // Tabellenspalte 'nachricht'
            [nachricht]
        ).
        execute(function(error, result) { // mySql Query ausführen
                if (error) {
                        console.log('ERROR: ' + error);
                        return;
                }
                console.log('Inserted id: ' + result.id);
        });
});
}

var server = net.createServer(function(socket){

        var sock_adr = socket.address();

        socket.write('Welcome on our Server. Port: ' + sock_adr.port);
        console.log('Socket open at' + sock_adr.port + '\n');

        var ausgabe = "";

        socket.on('data', function(data){ /* Ankommende Daten verarbeiten */

                socket.setEncoding("utf8"); /*Encoding ausgabe auf utf8 setzen*/
                ausgabe += data;
                        if(data == "\r\n"){ /*Wenn ENTER Usereingabe in DB schreiben! Carriage Return \r\n !!!*/
                              console.log(ausgabe);
                              insert_data(ausgabe); // Nachricht in Datenbank schreiben.
                              ausgabe = "";
                        }
        });
});

server.listen(8000,"0.0.0.0");