Skip to content

Commit

Permalink
feat(server): async server handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
bsrdjan committed Aug 5, 2023
1 parent 9d72919 commit 0b471bd
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 71 deletions.
7 changes: 4 additions & 3 deletions examples/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const server = new Server({ dest: "MME_GATEWAY" }, { dest: "MME" });
const delay = (seconds) =>
new Promise((resolve) => setTimeout(resolve, seconds * 1000));

function my_stfc_connection(request_context, abap_input) {
async function my_stfc_connection(request_context, abap_input) {
const connection_attributes = request_context["connection_attributes"];
console.log(
"[js] stfc context :",
Expand All @@ -16,14 +16,15 @@ function my_stfc_connection(request_context, abap_input) {
connection_attributes["progName"]
);
console.log("[js] stfc request :", abap_input);
for (let i = 1; i < 1000000000; i++) x = i / 3;
//const x = (async () => await delay(5))();
// for (let i = 1; i < 1000000000; i++) x = i / 3;
await delay(3);
abap_output = {
REQUTEXT: abap_input.REQUTEXT,
ECHOTEXT: abap_input.REQUTEXT,
RESPTEXT: `~~~ ${abap_input.REQUTEXT} ~~~`,
};
console.log("[js] stfc response:", abap_output);
//throw new Error("some error");
return abap_output;
}

Expand Down
42 changes: 7 additions & 35 deletions src/cpp/Log.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ namespace node_rfc {

#define SERVER_LOGFILE "_noderfc.log"

enum class logClass { client, pool, server, throughput };
enum class logSeverity { info, warning, error };
enum logClass { client = 0, pool, server, throughput };
enum logSeverity { info = 0, warning, error };

long long timestamp() {
using namespace std;
Expand All @@ -24,44 +24,16 @@ long long timestamp() {
}

template <typename... Args>
void _log(logClass component, logSeverity severity, Args&&... args) {
void _log(logClass component_id, logSeverity severity_id, Args&&... args) {
using namespace std;
string component_name;
string severity_name;
switch (component) {
case logClass::client:
component_name = "client";
break;
case logClass::server:
component_name = "server";
break;
case logClass::pool:
component_name = "pool";
break;
case logClass::throughput:
component_name = "throughput";
break;
default:
component_name = "component?";
}
switch (severity) {
case logSeverity::info:
severity_name = "info";
break;
case logSeverity::warning:
severity_name = "warning";
break;
case logSeverity::error:
severity_name = "error";
break;
default:
severity_name = "severity?";
}
const string component_names[4] = {"client", "pool", "server", "throughput"};
const string severity_names[3] = {"info", "warning", "error"};
ofstream ofs;
ofs.open(SERVER_LOGFILE, ofstream::out | ios::app);
time_t now = time(nullptr);
ofs << put_time(localtime(&now), "%F %T [") << timestamp() << "] ";
ofs << component_name << " (" << severity_name << ") ";
ofs << component_names[component_id] << " (" << severity_names[severity_id]
<< ") ";
(ofs << ... << args);
ofs << endl;
ofs.close();
Expand Down
100 changes: 68 additions & 32 deletions src/cpp/Server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -693,13 +693,46 @@ void Server::UnlockMutex() {
// uv_sem_post(&invocationMutex);
}

using DataType = ServerRequestBaton*;

// Transform JavaScript parameters' data to ABAP
Napi::Value processResult(Napi::Env env,
Napi::Value jsResult,
DataType requestBaton) {
Napi::Value errorObj = env.Undefined();
Napi::Object params = jsResult.As<Napi::Object>();
Napi::Array paramNames = params.GetPropertyNames();
uint_t paramSize = paramNames.Length();

for (uint_t i = 0; i < paramSize; i++) {
Napi::String name = paramNames.Get(i).ToString();
Napi::Value value = params.Get(name);
// DEBUG(name, value);
errorObj = setRfmParameter(requestBaton->func_desc_handle,
requestBaton->func_handle,
name,
value,
&requestBaton->errorPath,
&requestBaton->client_options);

if (!errorObj.IsUndefined()) {
break;
}
}
// Let genericRequestHandler return result to ABAP
requestBaton->done();

// Return error, if any
return errorObj;
}

// Thread safe call of JavaScript handler.
// Request "baton" is used to pass ABAP data and for
// waiting until JavaScript handler processing completed
// Request "baton" is used to pass ABAP data and
// wait until JavaScript handler processing completed
void JSFunctionCall(Napi::Env env,
Napi::Function callback,
std::nullptr_t* context,
ServerRequestBaton* requestBaton) {
DataType requestBaton) {
UNUSED(context);

// set server context
Expand Down Expand Up @@ -727,43 +760,46 @@ void JSFunctionCall(Napi::Env env,
// Call JavaScript handler
_log(logClass::server,
logSeverity::info,
"JS call start ",
"JS call ",
requestBaton->jsFunctionName,
" with ABAP function handle ",
(uintptr_t)requestBaton->func_handle);
Napi::Value result = callback.Call({requestContext, abapArgs});
(uintptr_t)requestBaton->func_handle,
" started");

Napi::Value jsResult = callback.Call({requestContext, abapArgs});

_log(logClass::server,
logSeverity::info,
"JS call end ",
"JS call ",
requestBaton->jsFunctionName,
" with ABAP function handle ",
(uintptr_t)requestBaton->func_handle);

// Transform JavaScript parameters' data to ABAP
Napi::Object params = result.ToObject();
Napi::Array paramNames = params.GetPropertyNames();
uint_t paramSize = paramNames.Length();

errorObj = env.Undefined();
for (uint_t i = 0; i < paramSize; i++) {
Napi::String name = paramNames.Get(i).ToString();
Napi::Value value = params.Get(name);
// DEBUG(name, value);
errorObj = setRfmParameter(requestBaton->func_desc_handle,
requestBaton->func_handle,
name,
value,
&requestBaton->errorPath,
&requestBaton->client_options);
(uintptr_t)requestBaton->func_handle,
" returned ",
(jsResult.IsPromise()) ? "promise" : "data");

if (jsResult.IsPromise()) {
// JS server function returned promise
Napi::Promise jsPromise = jsResult.As<Napi::Promise>();
Napi::Function jsThen = jsPromise.Get("then").As<Napi::Function>();
jsThen.Call(jsPromise,
{Napi::Function::New(env,
[=](const CallbackInfo& info) {
Object result = info[0].As<Object>();
processResult(env, result, requestBaton);
}),
Napi::Function::New(env,
[=](const CallbackInfo& info) {
Object result = info[0].As<Object>();
UNUSED(result);
// todo error handling
})

});

if (!errorObj.IsUndefined()) {
break;
}
} else {
// JS server function returned data
processResult(env, jsResult, requestBaton);
}

// Release the mutex, so that genericRequestHandler can return the result
// to ABAP
requestBaton->done();
}

} // namespace node_rfc
2 changes: 1 addition & 1 deletion src/cpp/noderfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//
// Logging
//
// #define LOG_RFC_CLIENT 1
#define LOG_RFC_CLIENT 1

#ifdef LOG_RFC_CLIENT
// Version unit test will fail, preventing the release with activated logging
Expand Down

0 comments on commit 0b471bd

Please sign in to comment.