Skip to content

Latest commit

 

History

History
952 lines (719 loc) · 36.9 KB

usage.md

File metadata and controls

952 lines (719 loc) · 36.9 KB

Data Types

Node.js data types are automatically converted to ABAP data types and vice versa:

Node.js to ABAP ABAP ABAP to Node.js Client Option
Number INT Number
String CHAR String
String STRING String
Buffer BYTE Buffer
Buffer XSTRING Buffer
String | Function DATE String | Function "date"
String | Function TIME String | Function "time"
String UTCLONG String
String NUM String
String | Number | Object FLOAT Number
String | Number | Object BCD String | Number | Function "bcd"
String | Number | Object DECF16 String | Number | Function "bcd"
String | Number | Object DECF34 String | Number | Function "bcd"

References:

Numeric types

ABAP built-in numeric types are mapped to JavaScript Number Objects.

Binary ABAP float type, FLOAT, is converted to Node.js Number Object. Number, String, or Number Object can be sent from Node.js to ABAP.

Decimal ABAP float types, BCD, DECF16 and DECF34, are represented as Node.js Strings by default.

Optionally represented as the Number Object, or custom decimal number object like Decimal, see client option "bcd".

Binary types

ABAP binary types, BYTE and XSTRING, are mapped to Node.js Buffer objects.

Date/Time types

ABAP date and time types, DATS and TIMS, are character types in ABAP, represented as Node.js String by default.

Optionally represented as custom Date/Time objects, see client options "date" and "time".

UTCLONG

ABAP UTCLONG type is mapped to Node.js string, with initial value 0000-00-00T00:00:00.0000000.

ABAP Function Module

Remote enabled ABAP function modules (RFM) parameters can be ABAP variables, structures and tables.

ABAP variables are mapped to Node.js variables, ABAP structures to Node.js objects (simple key-value pairs) and ABAP tables to Node.js arrays of objects, representing ABAP structures.

Taking ABAP RFM STFC_STRUCTURE as example, we see four parameters:

FUNCTION STFC_STRUCTURE.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*"       IMPORTING
*"             VALUE(IMPORTSTRUCT) LIKE  RFCTEST STRUCTURE  RFCTEST
*"       EXPORTING
*"             VALUE(ECHOSTRUCT) LIKE  RFCTEST STRUCTURE  RFCTEST
*"             VALUE(RESPTEXT) LIKE  SY-LISEL
*"       TABLES
*"              RFCTABLE STRUCTURE  RFCTEST
*"----------------------------------------------------------------------
Parameter name Direction Parameter type
IMPORTSTRUCT to ABAP structure
ECHOSTRUCT from ABAP structure
RESPTEXT from ABAP variable
RFCTABLE to/from ABAP table

Using ABAP transaction SE37 in ABAP backend system, you can enter the input data, run the function module and inspect results.

To consume this function module from Node.js, first the node-rfc client connection shall be instantiated, using ABAP backend system connection parameters.

Addon

API: api/addon

setIniFileDirectory

Sets the directory in which the NWRFC SDK shall search for the sapnwrfc.ini file, exposing the RfcSetIniPath NWRFC SDK method. The default is the current working directory of the process. After the directory is set, the NW RFC lib automatically loads the contents of the new sapnwrfc.ini file from that directory. The exception is thrown if sapnwrfc.ini not found in the new directory.

const noderfc = require("node-rfc");
noderfc.setIniFileDirectory("/some/folder");

reloadIniFile

Reloads the contents of the sapnwrfc.ini file into memory.

Searches the directory given by RfcSetIniPath() (or the current working directory) for the file sapnwrfc.ini and loads its contents into memory. Reloading the sapnwrfc.ini file is only necessary after the file has been manually edited. If you want to use a sapnwrfc.ini file in a different location, consider using setIniFileDirectory().

Note: If a file with the name sapnwrfc.ini does not exist in the given directory, this is not considered an error! Default settings are used in this case.

const noderfc = require("node-rfc");
try{
noderfc.reloadIniFile();
} catch (ex) {
    console.log(ex);
}

loadCryptoLibrary

Sets the absolute path to the sapcrypto library to enable TLS encryption via Websocket RFC.

The parameter pathToLibrary needs also to contain the name of the library. This function has the same effect as the sapnwrfc.ini parameter TLS_SAPCRYPTOLIB. This API cannot reset a new path to the library during runtime. Once set, the path is definitive.

const noderfc = require("node-rfc");
noderfc.loadCryptoLibrary("/usr/local/sap/cryptolib/libsapcrypto.so");

cancelClient

API: api/client

Cancels ongoing RFC call, see also: Cancel connection

const noderfc = require("node-rfc");
noderfc.cancelClient(client);

languageIsoToSap

API: api/addon

Conversion of language ISO code to 1-digit SAP code

const noderfc = require("node-rfc");
const langSAP = noderfc.languageIsoToSap("EN");

languageSapToIso

API: api/addon

Conversion of language 1-digit SAP code to ISO code

const noderfc = require("node-rfc");
const langSAP = noderfc.languageSapToIso("E");

Client

API: api/client

Using the client instance, ABAP RFMs can be consumed from Node.js. The client constructor requires connection parameters to ABAP backend system and, optionally, client options.

Connection Parameters

Connection parameters are provided as simple Node.js object. The complete list of supported parameters is given in sapnwrfc.ini file, located in SAP NWRFC SDK demo folder.

const abapConnection = {
    user: "demo",
    passwd: "welcome",
    ashost: "10.68.110.51",
    sysnr: "00",
    client: "620",
    lang: "EN",
};

Connection parameters can be also read from sapnwrfc.ini file, located in a current folder or at path set in RFC_INI environment variable (including the filename). Only the destination parameter is required:

const abapConnection = {
    dest: "QI3",
};

sapnwrfc.ini

DEST=QI3
USER=demo
PASSWD=welcome
ASHOST=10.68.110.51
SYSNR=00
CLIENT=620
LANG=EN
#TRACE=3
$ echo $RFC_INI
./sapnwrfc.ini

Direct and Managed Clients

The type of client connection can be managed (by the Connection Pool) or direct, without using Connection Pool.

The direct client is instantiated with closed connection:

const connParams = { dest: "QI3" };
const Client = require("node-rfc").Client;
const client = new Client(connParams);
console.log(client.alive); // false

Managed client is instantiated with open connection:

const Pool = require("node-rfc").Pool;
const pool = new Pool({ connectionParameters: connParams });
pool.acquire((client) => {
    console.log(client.alive); // true
});

An open connection is represented by unique RFC_CONNECTION_HANDLE pointer, assigned by SAP NWRFC SDK and exposed as a client connectionHandle getter. The value of this property is zero, when the connection is closed. The client getter alive is set to true, if the value is non-zero, representing an open connection.

Direct clients have access to connection open() and close() methods and each call toopen() method will set the new connectionHandlevalue. After the connection is closed, theconnectionHandle is set to zero but new opened connection can get the same connectionHandle value, as the previously closed connection. The handle is just the pointer to the C ++ object and after a free / delete operation the C-Runtime can re-use the same address again in a subsequent malloc / new. It happens very often (especially on Windows), that memory management system “notices” the block of memory is just the right size and the block is re-used, instead of allocating a new one, causing unnecessary fragmentation. The connectionHandle can therefore change during the direct client instance lifecycle and more client instances may get the sameconnectionHandle, not at the same time. If not synchronized properly, the delayed direct client close() call, can close the handle already assigned to another client instance, typically causing the RFC_INVALID_HANDLE errors when that client tries to make the RFC call.

This situation may happen when the node-rfc is consumed by multi-threaded nodejs modules, like express for example, when application typically can't influence the sequence of concurrent requests` execution.

Using Connection Pool is reccomended in such scenarios.

Client options

Using client options, passed to Client or Pool constructor, the default client behaviour can be modified:

Option Description
stateless Stateless connections, default false
bcd Decimal numbers conversion: Numeric types
date Dates conversion: Date/Time types
time Times of day conversion: Date/Time types
filter Result parameter types' filtering
timeout RFC call will be cancelled after timeout given in seconds. See Cancel connection

Stateless communication option "stateless"

When set to true, the RfcResetServerContext() is automatically executed after each RFM call from node-rfc. It can be also executed any time, by calling the client resetServerContext() method.

SAP NetWeaver RFC SDK ProgrammingGuide:

SAP Java Connector (JCo 3.1) and SAP .NET Connector (NCo 3.0) are stateless by default and you have to put some effort into it, if you need a stateful connection.

SAP NWRFC SDK and hence the node-rfc is statefull by default, which makes calling an Update-BAPI or some other RFM that stores intermediate results in the current user’s ABAP session memory very easy. For example, the program just calls the BAPI or function module, and if it succeeds, just calls BAPI_TRANSACTION_COMMIT on the same connection, and it will run inside the same user session in the backend.

However, there are also situations, where the business logic needs a stateless connection, for example, if you have just called a function module that stored a lot of data in the ABAP session memory, you now want to call further RFMs in the same user session, and the leftover data from the previous call is now superfluous garbage that is no longer needed, which degrades the performance, or – even worse – causes unwanted side effects for the following call(s).

Of course, the application could simply close the connection and open a fresh one, which also creates a fresh ABAP user session, but this could be a bit time and resource consuming, especially when an SNC handshake must be performed during login. In this case it is easier to just use the API function RfcResetServerContext(). This function cleans up any user session state in the backend, but keeps the connection and the user session alive.

Decimal data conversion option "bcd"

With bcd, set to number, or to conversion function like Decimal, decimal ABAP float types, BCD, DECF16 and DECF34 are represented as Number object or custom decimal number object.

❗ Using number option is not recommended here, can lead to rounding errors during ABAP to Node.js conversion.

let clientOptions = {
    bcd: "string",
    // bcd: require("decimal.js"),
};

Date and time conversion options "date" and "time"

The client option date shall provide fromABAP() function, for ABAP date string (YYYYMMDD) conversion to Node.js date object and the toABAP() function, for the other way around.

3rd party libraries like Moment or standard JavaScript Date Object can be used, like shown below:

const clientOptions = {
    date: {
        // Node.js Date() to ABAP YYYYMMDD
        toABAP: function (date) {
            if (!(date instanceof Date))
                return new TypeError(`Date object required: ${date}`);
            let mm = date.getMonth() + 1;
            let dd = date.getUTCDate();
            return [
                date.getFullYear(),
                mm > 9 ? mm : "0" + mm,
                dd > 9 ? dd : "0" + dd,
            ].join("");
        },

        fromABAP: function (dats) {
            // ABAP YYYYMMDD to Node.js Date()
            return new Date(
                0 | dats.substring(0, 4),
                (0 | dats.substring(4, 6)) - 1,
                (0 | dats.substring(6, 8)) + 1
            );
        },
    },
};

Parameter type filter option "filter"

Using the filter options, certan ABAP parameter types can be removed from RFM call result JavaScript object, reducing the data volume.

Supported values are described in sapnwrfc.h file, located in SAP NWRFC SDK include folder:

typedef enum _RFC_DIRECTION
{
  RFC_IMPORT   = 0x01,                    ///< Import parameter. This corresponds to ABAP IMPORTING parameter.
  RFC_EXPORT   = 0x02,                    ///< Export parameter. This corresponds to ABAP EXPORTING parameter.
  RFC_CHANGING = RFC_IMPORT | RFC_EXPORT, ///< Import and export parameter. This corresponds to ABAP CHANGING parameter.
  RFC_TABLES   = 0x04 | RFC_CHANGING      ///< Table parameter. This corresponds to ABAP TABLES parameter.
}RFC_DIRECTION
clientOptions = {
    filter: 1 // Import parameters not copied to result object
}

RFC call options

RFC call options can be provided for each particular RFC call:

  • notRequested
  • timeout

notRequested

ABAP remote-enabled function module can have many parameters but ABAP client calling the RFM may request only a few. When called by ABAP client, the ABAP RFM "knows" which parameters are requested and can skip processing and return of non-requested parameters. When called by non-ABAP client, not-requested parameters can be explicitely provided as array of parameters' names.

const notRequested = [
  "ET_COMPONENTS",
  "ET_HDR_HIERARCHY",
  "ET_MPACKAGES",
  "ET_OPERATIONS",
  "ET_OPR_HIERARCHY",
  "ET_PRTS",
  "ET_RELATIONS",
];
client.call(
  "EAM_TASKLIST_GET_DETAIL",
  {
    IV_PLNTY: "A",
    IV_PLNNR: "00100000",
  },
  {
    notRequested: notRequested,
  }
).then( ...

timeout

See Cancel connection

RFC call timeout overrides the client options timeout.

client.call(
  "EAM_TASKLIST_GET_DETAIL",
  {
    IV_PLNTY: "A",
    IV_PLNNR: "00100000",
  },
  {
    timeout: 5,
  }
).then( ...

Error Handling

Three types of errors can be returned to Node.js application:

  • JavaScript exceptions, thrown when wrong parameters are provided to Client, Pool or Throughput constructor
  • Error objects from NWRFC SDK, like logon error or calling a non-existing RFM
  • Error objects from node node-rfc, like catching a string passed from Node.js to ABAP RFM integer parameter field

After certain critical errors, the connection can be automatically re-opened: Closing connections.

Error object is returned as Promise rejection or first callback parameter (callback pattern).

When error is related to RFM parameter field, the rfmPath object is attached to error object, describing the affected field location:

const good = { RFCINT1: 1 };
const BAD = { RFCINT1: "1" };

client.invoke(
    "STFC_STRUCTURE",
    {
        RFCTABLE: [good, good, good, BAD, good],
    },
    (err, res) => {
        if (err) console.error("error:", err);
        //error: {
        //  name: 'nodeRfcError',
        //  message: 'Integer number expected from Node.js for the field of type 10',
        //  rfmPath: {
        //    rfm: 'STFC_STRUCTURE',
        //    parameter: 'RFCTABLE',
        //    table: 'RFCTABLE',
        //    table_line: 3,
        //    field: 'RFCINT1'
        //  }
        //}
    }
);

Error types, codes, groups, and classes

Schmidt and Li (2009a) describe five error types on the basis of the return code (i.e. error code), returned from NWRFC SDK:

  • Communication failure
  • Logon failure
  • System failure
  • ABAP exception
  • ABAP messages

There are in total roughly 30 possible return codes that indicate some kind of error. Error information returned from NWRFC SDK provides an error group, taken as the basis for two exception classes, shown in a below table. The node-rfc is using one exception class and exception class names are exposed as error object name property:

type (SPJ) code numeric group (C) Error Object name
Communication failure [1] RFC_COMMUNICATION_FAILURE COMMUNICATION_FAILURE RfcLibError
Logon failure [2] RFC_LOGON_FAILURE LOGON_FAILURE RfcLibError
System failure [3] RFC_ABAP_RUNTIME_FAILURE ABAP_RUNTIME_FAILURE AbapError
ABAP message [4] RFC_ABAP_MESSAGE ABAP_RUNTIME_FAILURE AbapError
ABAP exception [5] RFC_ABAP_EXCEPTION ABAP_APPLICATION_FAILURE AbapError
node-rfc error nodeRfcError

Invocation patterns

After getting a direct or managed client instance, the ABAP function module can be consumed from Node.js using Async/await, Promise or callback pattern.

Async/await

(async function () {
    try {
        await client.open();

        const importStruct = {
            RFCINT4: 345,
            RFCFLOAT: 1.23456789,
            RFCCHAR4: "ABCD",
            RFCDATE: "20180625",
        };

        let result = await client.call("STFC_STRUCTURE", {
            IMPORTSTRUCT: importStruct,
        });

        console.log(result.RESPTEXT);
    } catch (ex) {
        console.error(ex);
    }
})();

Promise

client
    .open()
    .then(() => {
        let importStruct = {
            RFCINT4: 345,
            RFCFLOAT: 1.23456789,
            RFCCHAR4: "ABCD",
            RFCDATE: "20180625",
        };
        client
            .call("STFC_STRUCTURE", { IMPORTSTRUCT: importStruct })
            .then((result) => {
                console.log(result.RESPTEXT);
            })
            .catch((err) => {
                console.error("could not complete ABAP RFM call", err);
            });
    })
    .catch((err) => {
        console.error("could not connect to server", err);
    });

Callback

// open connection
client.connect(function (err) {
    if (err) {
        // abort if login/connection errors
        return console.error("could not connect to server", err);
    }

    // invoke the function module
    const importStruct = {
        RFCINT4: 345,
        RFCFLOAT: 1.23456789,
        RFCCHAR4: "ABCD",
        RFCDATE: "20180625",
    };

    client.invoke(
        "STFC_STRUCTURE",
        { IMPORTSTRUCT: importStruct },
        (err, result) => {
            if (err) {
                return console.error("Error invoking STFC_STRUCTURE:", err);
            }

            console.log(
                "STFC_STRUCTURE call result", Object.keys(result))
            );
        }
    );
});

Connection Pool

API: api/pool

Connection Pool provides managed clients, which can't close or open their own connections. Their access to close() and open() methods is disabled and only the pool can open and close connections. The connectionHandle of the managed client is therefore constant, changed only after critical errors, leading to connection close ( see Closing connections). The managed client acquires an open connection from the Connnection Pool, using acquire() method and after no more needed, returns it back to pool, using release() method. After getting the connection back, the Connection Pool can reset the context and keep it open, ready for the next client, or close the connection. If the number of ready connections is less than pool high threshold parameter, the returned connection is added to ready connections, otherwise closed. The low threshold parameters defines a minimum number of connections, the Pool should keep open, ready for clients:

const pool = new Pool({
    connectionParameters: connParams,
    clientOptions: {}, // optional
    poolOptions: { low: 2, high: 4 }, // optional
});

Using ready() method, the number of ready connections can be increased, ignoring the ready_high:

pool.ready(5).then(() => {
    // 5 ready connections
});

Pool Options

low is the minimum number of connections to keep open, accelerating client acquire() requests. Default: 2.

high is the maximum number of connections to keep open, "recycling" returned client connections. Default: 4.

Closing connections

The direct connection is closed by calling the client close() method or automatically, by client destructor.

The managed connection is returned to Connection Pool, using release() method and can be closed or reused by Connection Pool.

Connection Pool ready and leased connections are closed by Pool destructor.

The direct and managed connection can be automatically closed, if critical error occurs during the communication with ABAP backend system. The client connectionHandle property is set to NULL and alive to false. Critical error conditions, leading to connection close, are exposed in errorInfo object.

If any of errors below occur, the client connection is not considered useful any more. The connection is automatically re-opened and in case re-open error, that error is returned as a result. The new connection handle is assigned to the client and, if the client is managed, the pool leased connections set is updated.

errorInfo Value Description
code RFC_COMMUNICATION_FAILURE Error in Network & Communication layer.
code RFC_ABAP_RUNTIME_FAILURE SAP system runtime error (SYSTEM_FAILURE): Shortdump on the backend side.
code RFC_ABAP_MESSAGE The called function module raised an E-, A- or X-Message.
code RFC_EXTERNAL_FAILURE Error in external custom code. (E.g. in the function handlers or tRFC handlers.) Results in SYSTEM_FAILURE.
group ABAP_RUNTIME_FAILURE ABAP Message raised in ABAP function modules or in ABAP runtime of the backend (e.g Kernel)
group LOGON_FAILURE Error message raised when logon fails
group COMMUNICATION_FAILURE Problems with the network connection (or backend broke down and killed the connection)
group EXTERNAL_RUNTIME_FAILURE Problems in the RFC runtime of the external program (i.e "this" library)

Cancel connection

Ongoing RFC call can be cancelled when running too long for example

  • Explicitely, by calling cancel() method, exposed at addon, client and pool level
  • By timeout provided in client options or RFC call options. RFC call timeout overrides the client timeout.

In either case, the sapnwrfc:cancel event is raised

Function call:

const client = await pool.acquire();

try {
const result = await client
        .call("RFC_PING_AND_WAIT", {
            SECONDS: N,
        })
} catch (err) {
    // raised when cancellation called:
    // {
    //    name: 'RfcLibError',
    //    group: 4,
    //    code: 7,
    //    codeString: 'RFC_CANCELED',
    //    key: 'RFC_CANCELED',
    //    message: 'Connection was canceled.'
    // }
}

Explicit cancel

await client.cancel();
await pool.cancel(client);
await addon.cancelClient(client);

Client with timeout client option will cancel all RFC calls taking longer than N seconds:

const client = new Client {dest: "XYZ", {timeout: N}}

Cancel by timeout

The timeout option can be provided also for at RFC call level, overriding the client timeout:

const client = new Client {dest: "XYZ", {timeout: 3}}

// A single RFC call can tolerate a longer duration
const result = await client.call("BAPI_USER_GET_DETAIL", {USERNAME: "DEMO"}, {timeout: 5});

// or shorter
const result = await client.call("BAPI_USER_GET_DETAIL", {USERNAME: "DEMO"}, {timeout: `});

Server

API: api/server

Blog: Call Node.js or Python Functions from ABAP

Using the node-rfc Server bindings, Node.js functions can be exposed as ABAP functions on Node.js system and consumed by ABAP client, using CALL FUNCTION DESTINATION ABAP statement.

To make Node.js function available for ABAP clients, the NodeJS function name must be mapped to valid ABAP function name (max 30 char long) that ABAP client can call. Also the description of ABAP function parameters must be provided (function description), in binary format, that ABAP client shall use to send and receive the data.

The ABAP function name is therefore not any name but the name of existing function module in ABAP system.This ABAP function can be already existing one, or new created empty function module, just for node-rfc Server function definition.

In following example the node-rfc server will expose two JS functions using function definitions of already existing ABAP function modules. The my_stfc_connection JS function is exposed as ABAP STFC_CONNECTION function module and my_stfc_structure as ABAP STFC_STRUCTURE function module.

The first JS function returns promise and the second one data value. Here is the example full source code:

and here the key points.

Node.js server program example

import { RfcLoggingLevel, Server } from "node-rfc";

// Create server instance
const server = new Server({
  clientConnection: { dest: "MME" },
  serverConnection: { dest: "MME_GATEWAY" },
  // Server options are not mandatory
  serverOptions: {
    logLevel: RfcLoggingLevel.info,
  },
});

// Define server function
function my_stfc_structure(request_context, abap_input) {
  return {
    ECHOSTRUCT: {RFCINT1: 2, RFCINT2: 6, RFCINT4: 16},
    RESPTEXT: `~~~ Node server here ~~~`
  }
}

(async () => {
  try {
    // Register my_stfc_structure as ABAP STFC_STRUCTURE function module
    await server.addFunction("STFC_STRUCTURE", my_stfc_structure);

    // Start the server
    await server.start();

  } catch (ex) {
      // Catch errors, if any
      console.error(ex);
  }
})();

// Close the server after 10 seconds - not for production!
let seconds = 10;
const tick = setInterval(() => {
  console.log("tick", --seconds);
  if (!seconds > 0) {
    server.stop(() => {
      clearInterval(tick);
      console.log("bye!");
    });
  }
}, 1000);

ABAP client call example

call function 'STFC_STRUCTURE' destination 'NWRFC_SERVER_OS'
  exporting
    importstruct = ...

Result

abap_call_result

Server logging

When activated the logging is save in _noderfc.log file in current working directory

Configuration

The ABAP system configuration for non-ABAP RFC server is described in chapter "5 RFC Server Programs" of SAP NWRFC SDK 7.50 Programming Guide

For this particular example, the configuration includes the two sets of ABAP RFC connection parameters, the clientConnection and serverConnection, as per our example:

const server = new Server({
  clientConnection: { dest: "MME" },
  serverConnection: { dest: "MME_GATEWAY" },

The client connection is required for fetching ABAP functions' definitions, not necessarily from the same system, from which the ABAP client shall call Node.js server.

The server connection is required for ABAP client to call Node.js server and may look like

Node server destinations

DEST=MME
USER=(redacted)
PASSWD=(redacte)
#ASHOST=coevi51
ASHOST=10.68.110.51
SYSNR=00
CLIENT=620
LANG=EN
TRACE=0

DEST=MME_GATEWAY
GWSERV=sapgw00
GWHOST=coevi51
PROGRAM_ID=RFCSERVER
REG_COUNT=1

ABAP client destinations (sm59)

The Node.js destination is in SM59 looks like

sm59

Throughput

API: api/throughput

The Throughput object can be attached to one or more clients, providing the RFM communication monitoring:

  • number of calls
  • sent bytes
  • received bytes
  • application time
  • total time
  • serialization time
  • deserialization time

Environment

The environment object provides info on node-rfc, SAP NWRFC SDK and Node.js platform.

It is exposed at package level, replicated at Pool and Client class and instance levels:

$ node -p "require('node-rfc')".environment         # binding
$ node -p "require('node-rfc')".Pool.environment    # class
$ node -p "require('node-rfc')".Client.environment  # class
$ node -p "new (require('node-rfc').Client)({dest: 'MME'}).environment" # instance
$ node -p "new (require('node-rfc').Pool)({connectionParameters: {dest: 'MME'}}).environment" # instance
{
    platform: { name: "darwin", arch: "x64", release: "19.5.0" },
    env: { SAPNWRFC_HOME: "/usr/local/sap/nwrfcsdk", RFC_INI: "" },
    noderfc: {
        version: "2.0.0",
        nwrfcsdk: { major: 7500, minor: 0, patchLevel: 5 },
    },
    versions: {
        node: "14.4.0",
        v8: "8.1.307.31-node.33",
        uv: "1.37.0",
        zlib: "1.2.11",
        brotli: "1.0.7",
        ares: "1.16.0",
        modules: "83",
        nghttp2: "1.41.0",
        napi: "6",
        llhttp: "2.0.4",
        openssl: "1.1.1g",
        cldr: "37.0",
        icu: "67.1",
        tz: "2019c",
        unicode: "13.0",
    },
}

Events

Client connection cancelled

Sent when client connection is cancelled, explicitely or by timeout.

import { Client, sapnwrfcEvents } from "node-rfc";

sapnwrfcEvents.on("sapnwrfc:clientCancel", (data) =>
    console.log("event", data)
);
// event { id: 1, connectionHandle: 140576595093504 }

Logging

Logging can be activated by Client, Pool or Server option logLevel, like:

const client = new Client(
    { dest: "MME" },
    {logLevel: RfcLoggingLevel.error });

const pool = new Pool({
  connectionParameters: { dest: "MME" },
  poolOptions: { logLevel: RfcLoggingLevel.error },
});

const server = new Server({
  serverConnection: { dest: "MME_GATEWAY" },
  clientConnection: { dest: "MME" },
  serverOptions: {
    logLevel: RfcLoggingLevel.debug,
  },
});

The default log file name is _noderfc.log, in current working directory. The different log file name and destination can be set by invoking addon method setLogFilePath(), like:

addon.setLogFilePath("/usr/local/tmp/mylogfile.log");