NodeJS Static function is not a function - javascript

I made a NodeJS application which usere a static Method to do some calculation Function.
When i try to acces the Method i got the isNotAFunction Error.
Here a static class which causes the error while accessing it:
exports.module = class PlaceEvaluator
{
static testMethod()
{
console.log("Test");
}
}
Here is the Code of the file which throws the Exception while reading:
PositionFinder = require("./positionFinder.js");
PlaceObj = require("./placeObj.js");
PlaceEvaluator = require("./placeEvaluator.js");
fetch = require("cross-fetch");
const express = require("express");
const http = require("http").createServer(express);
const io = require("socket.io")(http, {
cors:{
origin: "*"
}
});
const application = express();
application.use(express.static("public"));
PlaceEvaluator.testMethod();
io.on("connection", socket => {
socket.on("placeQuery", async ({topic, lat, long}) => {
PlaceEvaluator.testMethod(); //Here is the Exception function call
//console.log("Response sent!");
})
})
async function findPlaceObject(type, lat, long)
{
let placeObj = await PositionFinder.FetchPosition(type, lat, long);
return placeObj;
}
function convertToPlaceObjArr(inputObj)
{
var outputArr = [];
let name;
let lat;
let long;
for(var i = 0; i < inputObj.results.length; i++)
{
name = inputObj.results[i].name;
lat = inputObj.results[i].geometry.location.lat;
long = inputObj.results[i].geometry.location.lng;
outputArr.push(new PlaceObj(name, lat, long));
console.log(inputObj.results[i].name);
}
return outputArr;
}
http.listen(4000, function(){
console.log("Running on Port 4000");
// PositionFinder.FetchPosition("Pizza", "51.896359", "6.982303");
});

You need to use module.exports to export a default rather than exports.module.
By using exports.module you are exporting your class with the key of module so in that case you would have to do:
PlaceEvaluator.module.testMethod();

Related

Async export of redis client in nodejs

The following code constructs a redis client and exports. I am fetching the redis password from vault secret management service and that call is a promise/async. The code doesnt wait for that call and it exports the redis client before async call completes. I am not sure what I am doing wrong here. Any idea?
import redis from 'redis';
import bluebird from 'bluebird';
import logger from '../logger';
import srvconf from '../srvconf';
import { getVaultSecret } from '../services/vault.service';
const vaultConfig = srvconf.get('vault');
bluebird.promisifyAll(redis);
let redisUrl = '';
const maskRedisUrl = (url) => url.replace(/password=.*/, 'password=*****');
const setRedisUrl = (host, port, pw) => {
const pwstring = pw ? `?password=${pw}` : '';
const url = `redis://${host}:${port}${pwstring}`;
console.log(`Setting redis_url to '${maskRedisUrl(url)}'`);
return url;
}
if (vaultConfig.use_vault) {
(async () => {
const secret = await getVaultSecret(`${vaultConfig.redis.secrets_path + vaultConfig.redis.key}`)
redisUrl = setRedisUrl(srvconf.get('redis_host'), srvconf.get('redis_port'), secret.PASSWORD);
})().catch(err => console.log(err));
} else {
if (!srvconf.get('redis_url')) {
redisUrl = setRedisUrl(srvconf.get('redis_host'), srvconf.get('redis_port'), srvconf.get('redis_password'));;
} else {
redisUrl = srvconf.get('redis_url');
console.log(`Found redis_url ${maskRedisUrl(redisUrl)}`);
}
}
const options = redisUrl
? { url: redisUrl }
: {};
const redisClient = redis.createClient(options);
redisClient.on('error', err => {
logger.error(err);
});
export default redisClient;
The problem is that (async () => {...})() returns a Promise and you are not awaiting it at the top-level, so the script continues to run past that line, sets options = {} and returns the redisClient.
What you need is a top-level await which is enabled by default in Node versions >= 14.8.0. However, if your project uses a version older than that, there is a workaround as shown below.
Please note that the below code is NOT tested since I do not have the same project setup locally.
Module
import redis from "redis";
import bluebird from "bluebird";
import logger from "../logger";
import srvconf from "../srvconf";
import { getVaultSecret } from "../services/vault.service";
const vaultConfig = srvconf.get("vault");
bluebird.promisifyAll(redis);
let redisUrl = "";
let redisClient = null;
const initRedisClient = () => {
const options = redisUrl ? { url: redisUrl } : {};
redisClient = redis.createClient(options);
redisClient.on("error", (err) => {
logger.error(err);
});
};
const maskRedisUrl = (url) => url.replace(/password=.*/, "password=*****");
const setRedisUrl = (host, port, pw) => {
const pwstring = pw ? `?password=${pw}` : "";
const url = `redis://${host}:${port}${pwstring}`;
console.log(`Setting redis_url to '${maskRedisUrl(url)}'`);
return url;
};
(async () => {
if (vaultConfig.use_vault) {
try {
const secret = await getVaultSecret(
`${vaultConfig.redis.secrets_path + vaultConfig.redis.key}`
);
redisUrl = setRedisUrl(
srvconf.get("redis_host"),
srvconf.get("redis_port"),
secret.PASSWORD
);
} catch (err) {
console.log(err);
}
} else {
if (!srvconf.get("redis_url")) {
redisUrl = setRedisUrl(
srvconf.get("redis_host"),
srvconf.get("redis_port"),
srvconf.get("redis_password")
);
} else {
redisUrl = srvconf.get("redis_url");
console.log(`Found redis_url ${maskRedisUrl(redisUrl)}`);
}
}
// Initialize Redis client after vault secrets are loaded
initRedisClient();
})();
export default redisClient;
Usage
At all places where you import and use the client, you always need to check if it is actually initialized successfully, and throw (and catch) a well defined error if it is not.
const redisClient = require("path/to/module");
...
if (redisClient) {
// Use it
} else {
throw new RedisClientNotInitializedError();
}
...

How to pass object from one file to another in javascript?

I have node js server file (index.js) and client file (orderlist.js)
In index.js i am getting promise object , like that
function returnOrderArray() {
var i = 0;
const promise = new Promise((resolve, reject) => {
connection.query('SELECT * FROM orders', function(error, results) {
while (i < results.length) {
order.id[i] = results[i].id;
order.wavetype[i] = results[i].wavetype;
order.color[i] = results[i].color;
order.thick[i] = results[i].thick;
order.readydate[i] = results[i].readydate;
order.createdate[i] = results[i].createdate;
order.manager[i] = results[i].manager;
i++;
}
resolve(order);
// console.log(order);
});
});
return promise;
}
then i want to pass it to other js file.
I tried to do that with module.exports
app.get('/orderlist', checkUserSession, async function(request, response) {
returnOrderArray().catch(error => console.log(error)).then((() => {
module.exports.order = order;
response.render("orderlist.ejs", { username: request.session.username });
})).catch(error => console.log(error));
});
and then import it in orderlist.js
var ind = require('../../index')
function asd() {
alert(ind.order);
}
but it seems not to work.
What am i doing wrong , and what's the best way to pass objects to other files in js?
oh , and file architecture
filearch
You need to export your module like so: module.exports = returnOrderArray
try this,
orderlist.js
const returnOrderArray = () => {...some code..}
module.exports = returnOrderArray
index.js
const returnOrderArray = require('./path/to/orderlist.js')
const run = async() => {
const orderlist = await returnOrderArray() // use await or then as you prefer
}
run()
async_await link if curious!
Hope this will work :)

Parsing from JSON array, two objects

So I thought about using Jquery, and using the getJSON but I couldn't quite figure out how to get it to work, basically what I am trying to achieve is get the ['statename'], and the ['city'].
I was wondering what would be the.. simplest way to get them, and then have each of those results saved into ['statename'], and ['city']
So that way I can call them back in the url as ${statename} and ${city}..
Here's the code I have so far :
scripts.js
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
const {latitude, longitude} = position.coords;
let pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
const currentLocation = `https://geocode.xyz/${latitude},${longitude}?json=1`
console.log(currentLocation)
})};
scrapper.js
debug = require ('../models/conn');
const puppeteer = require('puppeteer');
const axios = require('axios');
const cheerio = require('cheerio');
async function searchJobs(i) {
const url = await axios.get('https://indeed.com/jobs?q=Web+Developer&l=Atlanta&fromage=last')
// return fetch(`${url}${i}`)
.then(response => response)
.then(res => {
const jobs = [];
const $ = cheerio.load(res.data);
$('.result').each((index, element) => {
const title = $(element).children('.title').text();
const linkToJob = $(element).children('.title').children('a').attr('href')
const body = $(element).children('.summary').text();
jobs[index] = { title, linkToJob, body };
});
console.log(jobs);
return jobs;
// Prints tbe second child of results class results for that page in console.
// console.log($('.result').children().eq(1).text());
});
return url;
};
// async function userCity(lat, long){
// const currentLocation = `https://geocode.xyz/${lat},${long}?json=1`
// await axios.get(currentLocation).then(response => {
// console.log(response['city'], response['statename']);
// })
// }
module.exports = searchJobs;
If you need or are wondering about the view files ask, I think these are the only two files really relevant to the question.. thank you :)
If I'm going to receive down votes, should at-least let me know why
Fixed it with the following code..
$.getJSON(`https://geocode.xyz/${latitude},${longitude}?json=1`, function (data) {
let state = `${data.statename}`
let city = `${data.city}`
console.log(state)
console.log(city)
});

How to use util.promisify to promisify a function in NodeJs?

I am trying to convert a Callback function into a Promise,
I'm using util.promisify for this and following is my working code vs the new non working one.
Working code, using Node Callback style -
let AWS = require(aws-sdk');
let moduleName = process.env.Module;
module.exports = {
getConstants
};
function getConstants (callback) {
let client = new AWS.SSM({
region: "us-east-1"
});
let smName = "/somePath";
let params = {
Names: [smName]
};
client.getParameters(params, function (err, data) {
if (err) {
console.log(err, err.stack);
callback(err, null);
}
else{
console.log(METHOD_TAG,'Parameter Store call successful!');
let constantVariables = data.Parameters[0].Value;
callback(null, constantVariables);
}
});
}
New Non working code -
let AWS = require('aws-sdk');
let util = require('util');
let moduleName = process.env.Module;
module.exports.getConstants = async () => {
let client = new AWS.SSM({
region: "us-east-1"
});
let smName = "/somePath";
let params = {
Names: [smName]
};
let parameterStore = util.promisify(client.getParameters).bind(client);
let response = await parameterStore.getParameters(params);
let constantVariables = response.Parameters[0].Value;
return constantVariables;
};
I am getting the following error -
TypeError: parameterStore.getParameters is not a function"
when trying to promisify the getParameters function of the AWS.SSM client.
What am I doing wrong, what should I change?
Reference -
https://medium.com/#suyashmohan/util-promisify-in-node-js-v8-d07ef4ea8c53
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SSM.html#getParameters-property

javascript classes call function

I am beginner in programming and I am trying the javascript classes, I want to call the boardCastinit function from the override function onConnMessage, but I am getting this error message, Please help in this issue.
boReferenceError: boardCastInit is not defined
websocket.js
class websocket extends webSocketModel {
constructor() {
let server = new Server();
let mongodb = new mongoDB();
super(server.server);
}
onConnMessage(message) {
let clients = this.clients;
boardCastInit(1);
}
boardCastInit(data){
console.log(data)
}
}
module.exports = websocket;
websocketModel.js
const ws = require('websocket').server;
class webSocketModel {
constructor(httpServer) {
if(!httpServer) throw 'Null Http Server';
this.websocket = new ws({ httpServer: httpServer, autoAcceptConnections: false });
this.websocket.on('request', this.onConnOpen.bind(this));
}
onConnOpen(request) {
var connection = request.accept('echo-protocol', request.origin);
console.log('Connection Accepted');
connection.on('message', this.onConnMessage);
connection.on('close', this.onConnClose);
}
onConnMessage(message) {
if (message.type === 'utf8') {
console.log(message.utf8Data);
} else if (message.type == 'binary') {
console.log(message.binaryData.length + 'bytes');
}
}
onConnClose(reasonCode, description) {
console.log('Connection Closed');
}
}
module.exports = webSocketModel;
just change boardCastInit(1) to this.boardCastInit(1)
onConnMessage(message) {
let clients = this.clients;
this.boardCastInit(1);
}
You should be calling it from the class this reference:
class websocket extends webSocketModel {
constructor() {
let server = new Server();
let mongodb = new mongoDB();
super(server.server);
}
onConnMessage(message) {
let clients = this.clients;
this.boardCastInit(1);
}
boardCastInit(data){
console.log(data)
}
}
module.exports = websocket;
You are missing this (should be this.boardCastInit(1)).
This could be a binding issue. Perhaps you want to use arrow function instead on your onConnMessage method:
onConnMessage = (message) => {
let clients = this.clients;
this.boardCastInit(1);
}
This will ensure that this refers to the websocket class which has the boardCastInit method defined.
Try binding the boardCastInit() function inside the constructor like this.
constructor() {
let server = new Server();
let mongodb = new mongoDB();
super(server.server);
this.boardCastInit = this.boardCastInit.bind(this);
}
Then call it from the this reference.
onConnMessage(message) {
let clients = this.clients;
this.boardCastInit(1);
}

Categories

Resources