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:
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".
ABAP binary types, BYTE and XSTRING, are mapped to Node.js Buffer objects.
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".
ABAP UTCLONG type is mapped to Node.js string, with initial value 0000-00-00T00:00:00.0000000
.
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.
API: api/addon
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");
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);
}
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");
API: api/client
Cancels ongoing RFC call, see also: Cancel connection
const noderfc = require("node-rfc");
noderfc.cancelClient(client);
API: api/addon
Conversion of language ISO code to 1-digit SAP code
const noderfc = require("node-rfc");
const langSAP = noderfc.languageIsoToSap("EN");
API: api/addon
Conversion of language 1-digit SAP code to ISO code
const noderfc = require("node-rfc");
const langSAP = noderfc.languageSapToIso("E");
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 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
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 connectionHandle
value. 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.
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 |
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.
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"),
};
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
);
},
},
};
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 can be provided for each particular RFC call:
notRequested
timeout
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( ...
RFC call timeout overrides the client options timeout.
client.call(
"EAM_TASKLIST_GET_DETAIL",
{
IV_PLNTY: "A",
IV_PLNNR: "00100000",
},
{
timeout: 5,
}
).then( ...
Three types of errors can be returned to Node.js application:
- JavaScript exceptions, thrown when wrong parameters are provided to
Client
,Pool
orThroughput
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'
// }
//}
}
);
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 |
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 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);
}
})();
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);
});
// 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))
);
}
);
});
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
});
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
.
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) |
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
- More info: Event: Client connection cancelled
- Examples: SAP/node-rfc-samples/clientConnectionCancel
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.'
// }
}
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}}
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: `});
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:
- ABAP client reports
- Server: server.mjs
- Log: _noderfc.log
and here the key points.
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);
call function 'STFC_STRUCTURE' destination 'NWRFC_SERVER_OS'
exporting
importstruct = ...
Result
When activated the logging is save in _noderfc.log
file in current working directory
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
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
The Node.js destination is in SM59 looks like
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
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",
},
}
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 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");