JSON.stringify fails on a newly created object (node, javascript) - javascript

Ok, this one has to be a very easy question, but I just started learning node. I am also new to javascript, so, please show no mercy on pointing out wrong directions below.
In particular I have two files:
one has a class that creates some slave servers in different ports
the other one is the "main" file that generates the slaves
When I attempt to print out what I have just initialized I get two weird errors:
connections property is deprecated. Use getConnections() method, and then
it crashes when I attempt to apply JSON.stringify in the new object (Converting circular structure to JSON)
Code for slaves in file "slave.js":
var http = require ("http");
function Slave () {
}
Slave.prototype.ID = undefined;
Slave.prototype.coordinator = false;
Slave.prototype.httpServer = undefined;
Slave.prototype.thePort = undefined;
Slave.prototype.isCoordinator = function () { return this.coordinator; }
/*****************************************************************/
function handle_incoming_request (req, res) {
console.log("INCOMING REQUEST: " + req.method + " " + req.url);
res.writeHead (200, { "Content-Type" : "application/json" });
res.end( JSON.stringify({ "error" : null }) + "\n" );
}
exports.createSlave = function (id, coordinatorK, port) {
var temp = new Slave ();
temp.ID = id;
temp.coordinator = coordinatorK;
temp.thePort = port;
temp.httpServer = http.createServer(handle_incoming_request);
temp.httpServer.listen (temp.thePort);
console.log ("Slave (" + (temp.isCoordinator() ? "coordinator" : "regular") + ") with ID " + temp.ID + " is listening to port " + temp.thePort);
console.log ("--------------------------------------------");
return temp;
}
Now, the main file.
var http = require ("http");
var url = require ("url");
var a = require ("./slave.js");
var i, temp;
var myArray = new Array ();
for (i = 0; i < 4; i++) {
var newID = i + 1;
var newPort = 8000 + i + 1;
var coordinatorIndicator = false;
if ((i % 4) == 0) {
coordinatorIndicator = true; // Say, this is going to be a coordinator
}
temp = a.createSlave (newID, coordinatorIndicator, newPort);
console.log ("New slave is : " + temp);
console.log ("Stringified is: " + JSON.stringify(temp));
myArray.push(temp);
}

You're trying to stringify the result of http.createServer(...). That'll not be what you want to do, so when you create that property, make it non-enumerable by defining it using Object.defineProperty().
exports.createSlave = function (id, coordinatorK, port) {
var temp = new Slave ();
temp.ID = id;
temp.coordinator = coordinatorK;
temp.thePort = port;
Object.defineProperty(temp, "httpServer", {
value: http.createServer(handle_incoming_request),
enumerable: false, // this is actually the default, so you could remove it
configurable: true,
writeable: true
});
temp.httpServer.listen (temp.thePort);
return temp;
}
This way JSON.stringify won't reach that property curing its enumeration of the object.

Issue is the with the property httpServer of temp object having circular reference. You can either set it non enumerable using Ecmascript5 property definision as mentioned in the previous answer or you can use the replacer function of JSON.stringify to customize it not to stringify the httpServer property.
console.log ("Stringified is: " + JSON.stringify(temp, function(key, value){
if(key === 'httpServer') return undefined;
return value;
}));

Related

javascript error in nifi executeScript

I am having an issue getting the javascript script for the executeScript nifi process to work and would appreciate help with this. The goal is to pass a flowfile which will contain a json object. I need to parse this json without knowing the content/fields prior and pass this along to write it out to the flowfile that is being passed out to the next process that is MergeContent and counts the number flowfiles.
Tried testing the script and got the following error:
nifi.script.ExecuteScript - ExecuteScript[id=bd6842e9-e3a4-4d88-a59d-
7da1d74d109b] ExecuteScript[id=bd6842e9-e3a4-4d88-a59d-7da1d74d109b]
failed to process due to
org.apache.nifi.processor.exception.ProcessException:
javax.script.ScriptException: <eval>:21:17 Expected : but found value
let value = json[key];
^ in <eval> at line number 21 at column number 17; rolling
back session: org.apache.nifi.processor.exception.ProcessException:
javax.script.ScriptException: <eval>:21:17 Expected : but found value
I am not very familiar with javascript so would appreciate the help.
flowFile = session.get();
if (flowFile != null) {
var StreamCallback =
Java.type("org.apache.nifi.processor.io.StreamCallback");
var IOUtils = Java.type("org.apache.commons.io.IOUtils");
var StandardCharsets = Java.type("java.nio.charset.StandardCharsets");
var transformed_message = {};
var error = false;
var line = "ops_testQueue";
flowFile = session.write(flowFile, new StreamCallback(function
(inputStream, outputStream) {
var content = IOUtils.toString(inputStream,
StandardCharsets.UTF_8); // message or content
var message_content = {};
try {
message_content = JSON.parse(content);
if(Array.isArray(message_content)){
}
Object.keys(message_content).forEach((key) => {
var value = json[key];
result.push(key + '=' + value);
var jkey = "," + "\"" + key + "\"" + '=' + value
});
line = line + jkey +
" value=" + "1"
+ " " + Date.now() * 1000000;
// Write output content
if (transformed_message) {
outputStream.write(line.getBytes(StandardCharsets.UTF_8));
}
} catch (e) {
error = true;
outputStream.write(content.getBytes(StandardCharsets.UTF_8));
}
}));
if (transformed_message.post_state) {
flowFile = session.putAttribute(flowFile, "type",
transformed_message.type);
}
if (error) {
session.transfer(flowFile, REL_FAILURE)
} else {
session.transfer(flowFile, REL_SUCCESS)
}
}
EDIT:
input to executeScript:
{"pID":"1029409411108724738",
"contentType":"text",
"published":"2018-08-14 16:48:23Z",
"crawled":"2018-08-14 12:48:33-04:00",
"ID":"765"}
output from executeScript:
ops_testQueue,"ID"=765 value=1 1534265314969999870
Am I missing something?
I saw a couple of things here:
I don't know if Nashorn (Java's JS Engine) supports the full lambda
syntax, I was able to get it to work by making the lambda a function
(see script below).
You refer to a json variable to get the value from a key, but I think you want message_content.
result is not defined, so you get an error when you push to it.
Here's an edited version of your script that I got to work the way I think you want it (but please correct me if I'm wrong):
flowFile = session.get();
if (flowFile != null) {
var StreamCallback =
Java.type("org.apache.nifi.processor.io.StreamCallback");
var IOUtils = Java.type("org.apache.commons.io.IOUtils");
var StandardCharsets = Java.type("java.nio.charset.StandardCharsets");
var transformed_message = {};
var error = false;
var line = "ops_testQueue";
flowFile = session.write(flowFile, new StreamCallback(function
(inputStream, outputStream) {
var content = IOUtils.toString(inputStream,
StandardCharsets.UTF_8); // message or content
var message_content = {};
try {
message_content = JSON.parse(content);
if(Array.isArray(message_content)){
}
var jkey = "";
Object.keys(message_content).forEach(function(key) {
var value = message_content[key];
//result.push(key + '=' + value);
jkey = "," + "\"" + key + "\"" + '=' + value
});
line = line + jkey +
" value=" + "1"
+ " " + Date.now() * 1000000;
// Write output content
if (transformed_message) {
outputStream.write(line.getBytes(StandardCharsets.UTF_8));
}
} catch (e) {
error = true;
log.error(e);
outputStream.write(content.getBytes(StandardCharsets.UTF_8));
}
}));
if (transformed_message.post_state) {
flowFile = session.putAttribute(flowFile, "type",
transformed_message.type);
}
if (error) {
session.transfer(flowFile, REL_FAILURE)
} else {
session.transfer(flowFile, REL_SUCCESS)
}
}

Cannot open file "/dev/ttyO2" when trying to use the serial port on the Beaglebone Black

I am trying to open the serial port 2 on my beagle bone, using the following code:
var b = require('bonescript');
var x = '/dev/ttyO2';
var SerialPort = require("serialport").SerialPort;
var serialPort = new SerialPort('/dev/ttyO2', {
baudrate: 115200,
parser: b.serialParsers.readline("\n")
});
The complete code:
var b = require('bonescript');
var x = '/dev/ttyO2';
var SerialPort = require("serialport").SerialPort;
var serialPort = new SerialPort('/dev/ttyO2', {
baudrate: 115200,
parser: b.serialParsers.readline("\n")
});
b.pinMode("P9_17", b.OUTPUT);
var countTry =2;
var i = 0; // to loop over the array
var waiting_interval = 3000; // waiting for every slave to reply
var deli;
var slaves = ["S1", "S2" , "S3", "S4", "S5", "S6"];
var counter=[0 , 0 , 0 , 0 ,0 ,0];
var slave_exists = false;
serialPort.on('open',function onSerialOpen(){
console.log("opened");
serialPort.on('data', function listenToSlaves(data){
i--;
if(data.search("END" + slaves[i]) ==0){
console.log("ENDED");
slave_exists = true;
counter[i]=0;
}
else{
// if(data!="END" + slaves[i]){
if(data.search("END" + slaves[i])!==0){
deli = data.indexOf(":");
var parameter = data.substring(0, deli);
var value = data.substring(deli +1);
console.log("parameter is: " + parameter + " - Value is: " + value);
}
}
if(slave_exists){
counter[i] =0;
}
i++;
});
writeToSlaves();
});
function writeToSlaves(){
//If the previous slave (the slave before the one I am sending to
//in the next step doesnt exist, add the counter or consideer
//it not existing)
if(!slave_exists){
counter[i-1]+=1;
if(counter[i-1]>=countTry){
console.log("--------counter[" + i + "]: " + counter[i]);
// in case that the slave returned no data after trying
//to send him several times
console.log(slaves[i-1] + " doesn't exist");
}
}
//sending to the following slave
b.digitalWrite("P9_17", b.HIGH);
serialPort.write(slaves[i], function(){ slave_exists = false;});
b.digitalWrite("P9_17", b.LOW);
console.log("I wrote to slave: " + i);
if(i<slaves.length - 1) i++;
else i=0;
setTimeout(writeToSlaves, waiting_interval);
}
but I am always facing this error:events.js:72
throw er; // Unhandled 'error' event
^
Error: Cannot open /dev/ttyO2
I am running another file first (the code down), the I try to rerun the previous code, and it runs perfect. I need to do that whenever I want to run the first code!
The code that runs from the first time is here:
( I tried the following code alone, it writes to the serial port but doesnt recieve, no event at recieption):
var b = require('bonescript');
var rxport = '/dev/ttyO2';
var txport = '/dev/ttyO2';
var options = { baudrate: 115200, parity: 'even', parser: b.serialParsers.readline('\n') };
var teststring = "This is the string I'm sending out as a test";
b.serialOpen(rxport, options, onRxSerial);
function onRxSerial(x) {
console.log('rx.eventrx= ' + x.event);
if(x.err) throw('***FAIL*** ' + JSON.stringify(x));
if(x.event == 'open') {
//readReapeatedly();
b.serialOpen(txport, options, onTxSerial);
}
if(x.event == 'data') {
console.log("I am receiving on rxport");
console.log('rx (' + x.data.length +
') = ' + x.data.toString('ascii'));
}
}
function onTxSerial(x) {
console.log('tx.event = ' + x.event);
if(x.err) throw('***FAIL*** ' + JSON.stringify(x));
if(x.event == 'open') {
writeRepeatedly();
}
if(x.event == 'data') {
// console.log('tx (' + x.data.length +
// ') = ' + x.data.toString('ascii'));
console.log(x.data);
}
}
function printJSON(x) {
console.log(JSON.stringify(x));
}
function writeRepeatedly() {
console.log("write to serial");
b.serialWrite(txport, teststring, onSerialWrite);
console.log("I have sent data");
}
function onSerialWrite(x) {
console.log("Iam in the onSerialWrite function");
if(x.err) console.log('onSerialWrite err = ' + x.err);
if(x.event == 'callback') {setTimeout(writeRepeatedly, 5000);
console.log("HERE");
}
}
The problem was solved.
In /boot/uboot/uEnv.txt, Update the line:"#cape_enable=capemgr.enable_partno= " to be:
"cape_enable=capemgr.enable_partno=BB-UART1,BB-UART2,BB-UART4, BB-UART5 "
or add the last line to the mentioned file. In some cases, you need to try this line instead of the mentioned:
"optargs=capemgr.enable_partno=BB-UART1,BB-UART2,BB-UART4, BB-UART5" (this is my case - but it disabled the HDMI interface of my BBB).
You can specify the UART you want to enable.
A helpful webpage is here.

Which headers do I have to pass on an JavaScript S3 AWS request using signature v4 and assumed role credentials?

I'm trying to make a REST connection to Amazon S3 and I'm struggling to implement the signature V4 process. I know, Amazon also provides a JavasScript an sdk, but I need to get it to work by myself.
To test my code, I'm using the AWS testsuite and my code successfully returns the expected results. However, all my real life attempts fail because of signature does not match error.
The issue for me is, the examples don't include any headers except host and date which is kind of straightforward. I'm having to pass the "full monty" including access tokens and I'm sure there is a problem with the headers.
Here is what I'm doing on click of a button:
function simpleS3Scenario(my_storage) {
return new RSVP.Queue()
.push(function () {
return my_storage.allDocs();
})
.push(function (my_alldocs_response) {
console.log("initial ALLDOCS")
console.log(my_alldocs_response);
})
...
};
allDocs will eventually run into this:
S3Storage.prototype.buildQuery = function (param, options) {
var context = this,
url = this._base_url,
url_path = this._bucket + "/",
headers,
requestText;
return new RSVP.Queue()
.push(function () {
return SigV4_custom.makeSignedRequest(
"GET",
url + url_path,
'',
{"max-key": 100, "prefix": "sample_folder"},
{},
context._region,
"s3",
"AWS4-HMAC-SHA256",
context._secret_access_key,
context._access_key,
context._session_token
);
})
.push(function (e) {
console.log("YUPI");
console.log(e);
})
...
which enters my request signature handler, which is based on this (not working with Signature v4) Amazon example | code: sigv4.js:
(sorry, not shortened yet, scroll down to ENTRY POINT, then work yourself up)
var SigV4_custom = new function(){
this.createCanonicalRequest = function(){};
this.createStringToSign = function(){};
this.generateSignatureAndSign = function(){};
this.makeSignedRequest = function(){};
}
// trim polyfill
String.prototype.trim = String.prototype.trim || function () {
var start = -1,
end = this.length;
while( this.charCodeAt(--end) < 33 );
while( this.charCodeAt(++start) < 33 );
return this.slice( start, end + 1 );
};
// =============== generator funtions =================
// generate query parameter string for canonical request
function generateCanonicalQueryString(my_parameter_dict) {
var canonical_query_string = '',
encoded_parameter_dict = {},
key_list = [],
key,
value,
i,
i_len;
// set and encode
for (key in my_parameter_dict) {
if (my_parameter_dict.hasOwnProperty(key)) {
value = my_parameter_dict[key];
if (typeof value === "object") {
encoded_parameter_dict[encodeURIComponent(key)] =
encodeURIComponent(value[0]) + '&';
// Append each additional value to the query parameter
for (i = 0, i_len = value.length; i < i_len; i += 1) {
encoded_parameter_dict[encodeURIComponent(key)] +=
encodeURIComponent(key) + '=' + encodeURIComponent(value[i]) +'&';
}
encoded_parameter_dict[encodeURIComponent(key)] =
encoded_parameter_dict[encodeURIComponent(key)].slice(0,-1);
} else {
encoded_parameter_dict[encodeURIComponent(key)] =
encodeURIComponent(value);
}
}
}
// then fill key_list
for (key in encoded_parameter_dict) {
if (encoded_parameter_dict.hasOwnProperty(key)) {
key_list.push(key);
}
}
key_list.sort();
for (i = 0, i_len = key_list.length; i < i_len; i += 1) {
canonical_query_string +=
key_list[i] + "=" + encoded_parameter_dict[key_list[i]] + "&";
}
return canonical_query_string.slice(0, -1);
}
// generate canonical header string
function generateCanonicalHeaderString(my_header_dict, is_signature) {
var canonical_header_string = '',
encoded_header_dict = {},
header_list = [],
header,
value,
trimmed_value,
header_lowercase,
i,
i_len,
separator,
connector,
format,
cutoff;
if (is_signature) {
cutoff = -1;
separator = ":";
connector = "\n";
format = function (my_value) {
return my_value.toLowerCase();
}
} else {
cutoff = -1;
separator = "=";
connector = "&";
format = function (my_value) {
return my_value;
}
}
// Take header keys and put in array, then sort and build
for (header in my_header_dict) {
if (my_header_dict.hasOwnProperty(header)) {
header_lowercase = format(header);
value = my_header_dict[header];
trimmed_value = undefined;
//XXX there are not only strings in the headers...
if (value.trim) {
trimmed_value = value.trim();
}
if (encoded_header_dict[header_lowercase] === undefined) {
encoded_header_dict[header_lowercase] = trimmed_value || value;
header_list.push(header_lowercase);
} else {
encoded_header_dict[header_lowercase] += "," + trimmed_value || value;
}
}
}
header_list.sort();
for (i = 0, i_len = header_list.length; i < i_len; i += 1) {
canonical_header_string +=
header_list[i] +
separator +
encoded_header_dict[header_list[i]] +
connector;
}
canonical_header_string = canonical_header_string.slice(0, cutoff);
return canonical_header_string;
}
// generate the signed header string
function generateSignedHeaderString(my_header_dict) {
var signed_header_string = '',
header_list = [],
header,
header_lowercase,
i,
i_len;
for (header in my_header_dict) {
if (my_header_dict.hasOwnProperty(header)) {
header_list.push(header.toLowerCase());
}
}
header_list.sort();
for (i = 0, i_len = header_list.length; i < i_len; i += 1) {
signed_header_string += header_list[i] + ';';
}
return signed_header_string.slice(0, -1);
}
// returns a timestamp in the YYYYMMDD'T'HHmmSS'Z' format, for SigV4 calls
function generateTimestamp() {
var date = new Date();
function bump(my_time_parameter) {
if (my_time_parameter.length === 1) {
return '0' + my_time_parameter;
}
return my_time_parameter;
}
// Assemble date, bump single digits to doubles
// validation: return "20130524T000000Z";
return date.getUTCFullYear() +
bump((date.getUTCMonth()+1).toString()) + // month
bump(date.getUTCDate().toString()) + // day
'T' +
bump(date.getUTCHours().toString()) + // hour
bump(date.getUTCMinutes().toString()) + // minute
bump(date.getUTCSeconds().toString()) + // second
'Z';
}
// generate the credential scope
function generateCredentialScope(my_timestamp, my_region, my_service) {
return my_timestamp.substring(0, 8) + "/" +
my_region + "/" +
my_service + "/" +
"aws4_request";
}
// ================== CORE methods ==================
SigV4_custom.createStringToSign = function (request_time, credential_scope,
canonical_request, signing_algorithm) {
// Step 1: designate the algorithm (for SigV4 it is SHA256)
// Step 2: designate the RequestDate (already done, passed to function)
// Step 3: create credentialScope (already done, passed to funtion)
return signing_algorithm + '\n' +
request_time + '\n' +
credential_scope + '\n' +
canonical_request;
}
SigV4_custom.generateSignatureAndSign = function(secret, request_time, region,
service, string_to_sign) {
var datestamp = request_time.substring(0, 8),
hash_date,
hash_region,
hash_service,
hash_signing,
request = 'aws4_request';
hash_date = CryptoJS.HmacSHA256(datestamp, 'AWS4' + secret, {asBytes: true});
hash_region = CryptoJS.HmacSHA256(region, hash_date, {asBytes: true});
hash_service = CryptoJS.HmacSHA256(service, hash_region, {asBytes: true});
hash_signing = CryptoJS.HmacSHA256(request, hash_service, {asBytes: true});
// sign and return
return CryptoJS.HmacSHA256(string_to_sign, hash_signing)
.toString(CryptoJS.enc.Hex);
}
SigV4_custom.createCanonicalRequest = function(method, pathname,
parameter_dict, header_dict, hashed_payload) {
var canonical_request = "",
http_request_method = "",
canonical_url = "",
canonical_query_string = "",
canonical_header_string = "",
signed_header_string = "",
payload;
// Step 1: Start with the HTTP request method
http_request_method = method;
// Step 2: Add the canonicalUrl parameter
canonical_url = pathname;
// Step 3: Add the canonicalQueryString parameter
canonical_query_string = generateCanonicalQueryString(parameter_dict);
// Step 4: Add the canonicalHeaders parameter
canonical_header_string = generateCanonicalHeaderString(header_dict, true);
// Step 5: Add the signedHeaders parameter
signed_header_string = generateSignedHeaderString(header_dict);
// Step 6: Add the hashed payload
payload = hashed_payload;
// Step 7: string together the canonicalRequest from steps 1 through 6
canonical_request += http_request_method + '\n' +
canonical_url + '\n' +
canonical_query_string + '\n' +
canonical_header_string + '\n\n' +
signed_header_string + '\n' +
payload;
return canonical_request;
};
// =================== ENTRY POINT ===================
// Call this function to make a SigV4 REST API call.
SigV4_custom.makeSignedRequest = function (method, path, payload,
parameter_dict, header_dict, region, service, signing_algorithm,
secret_access_key, access_key_id, security_token) {
var link = document.createElement("a"),
request_time = generateTimestamp(),
scope = generateCredentialScope(request_time, region, service),
authorization_string,
canonical_request,
string_to_sign,
request_uri,
signature;
// link is a location object, set its href to use its properties
link.href = path;
// set all headers, then generate a canonical_request
// payload must be hashed here, as this may vary and the hash is required
// for canonization and as a header. Empty payloads will hash an empty "".
header_dict['X-Amz-Content-Sha256'] = CryptoJS.SHA256(payload)
.toString(CryptoJS.enc.Hex);
header_dict['host'] = link.hostname;
header_dict['X-Amz-Date'] = request_time;
header_dict['X-Amz-Credential'] = access_key_id + "/" + scope;
header_dict['X-Amz-Security-Token'] = security_token;
header_dict['X-Amz-Algorithm'] = signing_algorithm;
header_dict['X-Amz-Expires'] = 86400;
// Task 1: Compute the canonical request
canonical_request = CryptoJS.SHA256(
this.createCanonicalRequest(
method,
link.pathname,
parameter_dict,
header_dict,
header_dict['X-Amz-Content-Sha256']
)
)
.toString(CryptoJS.enc.Hex);
// delete host because it is also in the headers (needs to be in both
// initially to create the canonicalization)
delete parameter_dict['host'];
// Task 2: Create the string to sign using the encoded canonical request
string_to_sign = this.createStringToSign(
request_time,
scope,
canonical_request,
signing_algorithm
);
// Task 3: Create the signature using the signing key and the string to sign
signature = this.generateSignatureAndSign(
secret_access_key,
request_time,
region,
service,
string_to_sign
);
// Task 4: Build the authorization header
header_dict['Authorization'] = header_dict['X-Amz-Algorithm'] +
" Credential=" + header_dict['X-Amz-Credential'] + "," +
"SignedHeaders=" + generateSignedHeaderString(header_dict) + "," +
"Signature=" + signature;
// Task 5: Make the request (through jIO)
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
"method": method,
"url": path,
"headers": header_dict
});
});
}
So when I run the Amazon samples with just two headers through this, I get correct signature and authorization header at the end. I believe I'm doing something wrong with the headers, especially which headers should go into the signature, but I can't find any good help online and am stuck on this for a few days now.
Question:
Maybe someone has an idea from looking at how I'm handling the headers, why my requests to AWS fail due to non-matching signature?
THANKS!
Edit:
I have used this Amazon Example page for deriving signatures. If I run the sample inputs through my createSignatureAndSign method, I can produce the same outputs. So my signature is correct an secret are correct.

Trouble assigning multiple nodejs exports return values to variables

I have two files, a main file and a module file. Inside the module file, I export two functions, which return objects. In the main file, I am setting a variable to the return value of each method. However, each variable is set to the return value of the last method called. What am I doing wrong here?
/* main file */
module.exports = function(robot) {
var startingCharacter = require('./data/starting/character.json'),
make = require('./includes/make.js');
return robot.respond(/dungeon me/i, function(msg) {
var character = startingCharacter,
weapon = make.weapon(0),
armor = make.armor(0);
console.log(weapon); // <- returns value from make.armor(0)
console.log(armor); // <- returns value from make.armor(0)
}
};
/* module file */
var random = require('./random.js');
var baseStats = {
'equipped': 'true',
'attack': '0',
'damage': '0',
'defense': '0',
'health': '0',
'luck': '0',
'passivePower': {},
'activePower': {}
};
// Generate a weapon
exports.weapon = function(level) {
var weaponNames = require('../data/nouns/weapon_names.json');
var thisWeapon = {};
if (level === 0) {
var adjNeg = require('../data/adjectives/negative.json');
thisWeapon = baseStats;
thisWeapon.name = adjNeg[random(0, adjNeg.length)] + ' ' + weaponNames[random(0, weaponNames.length)];
thisWeapon.type = 'weapon';
}
console.log(thisWeapon); // <- returns correct value
return thisWeapon;
};
// Generate armor
exports.armor = function(level) {
var armorNames = require('../data/nouns/armor_names.json');
var thisArmor = {};
if (level === 0) {
var adjNeg = require('../data/adjectives/negative.json'),
animals = require('../data/nouns/animals.json');
var armorName = armorNames[random(0, armorNames.length)];
thisArmor = baseStats;
if (armorName === 'Hide') {
thisArmor.name = animals[random(0, animals.length)] + ' ' + armorName + ' armor';
}
else {
thisArmor.name = adjNeg[random(0, adjNeg.length)] + ' ' + armorName;
}
thisArmor.type = 'armor';
}
console.log(thisArmor); // <- returns correct value
return thisArmor;
};
Note: edited with real code, instead of sample code
When you do this:
thisArmor = baseStats;
you're not making a copy of the "baseStats" object. Since both methods in the module modify and return a reference to that same object, you get the effect you observe.
There are several ways to implement a shallow copy operation for Node; see this Stackoverflow question. With one of those approaches, you'd start those methods off with a local copy of "baseStats".

How to iterate through all keys & values of nested object?

I am developing a web application in javascript (both on the server and client side). I am sending back and forth data as json, and I want to be able to parse it on the other side. The problem is that I have several levels of nested objects inside, so this is where I am stuck. For example, I am sending the following data:
var data = {};
data.title = "My Title";
data.metric = {
fact : "Malicious code detected",
technique : "XSS"
};
data.subject = {
userType : "ADMIN",
userName : "Jack",
clientNumber : "000",
terminal : "192.168.1.1"
};
data.context = {
environment : {
session : "00",
hostname : "mainServer",
sysType : "production"
},
resource : {
wpt : "DIA",
pid : "1024"
}
};
On the other side, when I receive it, I just want to be able to completely loop through this object, and print its contents. I have seen a lot of similar questions on stackoverflow, but none of them have been helpful. Here is what I have done so far:
function display(data) {
var resp = "";
var prop = null;
var dataJSON = JSON.parse(data);
for (prop in dataJSON) {
if (patternJSON.hasOwnProperty(prop)) {
resp += "obj" + "." + prop + " = " + dataJSON[prop] + "\n";
}
}
return resp;
}
But I do not know how to make it automatically go deeper, no matter the number of levels.
Can somebody point me to the right direction please?
Any help would be greatly appreciated! 10x
Define a print function
function print(obj, prefix) {
prefix = prefix || 'obj';
return Object.keys(obj).reduce(function(acc, key){
var value = obj[key];
if(typeof value === 'object') {
acc.push.apply(acc, print(value, prefix + '.' + key));
}
else {
acc.push(prefix + '.' + key + ' = ' + value);
}
return acc;
}, []);
}
And use it like this print(data).join('\n').
"obj.title = My Title
obj.metric.fact = Malicious code detected
obj.metric.technique = XSS
obj.subject.userType = ADMIN
obj.subject.userName = Jack
obj.subject.clientNumber = 000
obj.subject.terminal = 192.168.1.1
obj.context.environment.session = 00
obj.context.environment.hostname = mainServer
obj.context.environment.sysType = production
obj.context.resource.wpt = DIA
obj.context.resource.pid = 1024"

Categories