tunnel-ssh throws an error after getting connected - node.js

I'm trying to connect to mongodb(mongodb package) using the tunnel-ssh package. It gets connected and I can log the db but it immediately throws an error and disconnects.
buffer.js:705
throw new ERR_INVALID_ARG_TYPE(
^
TypeError [ERR_INVALID_ARG_TYPE]: The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type undefined
at Function.byteLength (buffer.js:705:11)
at SSH2Stream.directTcpip (D:\WORK\node_modules\ssh2-streams\lib\ssh.js:1128:23)
at openChannel (D:\WORK\node_modules\ssh2\lib\client.js:1142:21)
at Client.forwardOut (D:\WORK\node_modules\ssh2\lib\client.js:994:10)
at Client.<anonymous> (D:\WORK\node_modules\tunnel-ssh\index.js:16:23)
at Client.emit (events.js:223:5)
at SSH2Stream.<anonymous> (D:\WORK\node_modules\ssh2\lib\client.js:601:10)
at Object.onceWrapper (events.js:312:28)
at SSH2Stream.emit (events.js:223:5)
at parsePacket (D:\WORK\node_modules\ssh2-streams\lib\ssh.js:3911:10) {
code: 'ERR_INVALID_ARG_TYPE'
}
This is my code.
const tunnel = require("tunnel-ssh");
const config = require("config");
const MongoClient = require("mongodb").MongoClient;
const connection = new Promise((resolve, _) => {
// eslint-disable-next-line
tunnel(config.get("server"), async (err, server) => {
server.on("connection", console.log.bind(console, "server error"));
const client = await MongoClient.connect(config.get("mongodb").url, {
useUnifiedTopology: true,
useNewUrlParser: true
});
client.on("error", console.error.bind(console, "mongodb error"));
resolve({ client });
});
});
async function runQuery() {
const { client} = await connection;
console.log(client);
}
runQuery();
There is no problem with config. In fact, the logging in runQuery function works but throws that error immediately.

I have not used the tunnel-ssh package you have mentioned, but I went through the docs and I see that you are using it wrong. I simply copied the configuration given in the docs of tunnel-ssh and it started working for me. pasting the entire code below
const tunnel = require("tunnel-ssh");
const MongoClient = require("mongodb").MongoClient;
const connection = new Promise((resolve, _) => {
// eslint-disable-next-line
tunnel(
{
username: "root",
Password: "secret",
host: "127.0.0.1",
port: 22,
dstHost: "127.0.0.1",
dstPort: 27017,
localHost: "127.0.0.1",
localPort: 27000
},
async (err, server) => {
server.on("connection", console.log.bind(console, "server error"));
const client = await MongoClient.connect(
"mongodb://localhost:27017/user",
{
useUnifiedTopology: true,
useNewUrlParser: true
}
);
client.on("error", console.error.bind(console, "mongodb error"));
resolve({ client });
server.close();
}
);
});
async function runQuery() {
const { client } = await connection;
console.log("Connection Successful");
}
runQuery();
The part where you went wrong is passing string to tunnel package. it expects configuration object not string.

Related

Node.js/Express: How Do I Share or Export Mongo Database Connection To Other Modules?

I am trying to share the Mongo connection with other modules in my Node.js project. I keep getting either undefined or is not a function when attempting to use the exported client. I also had a question around detecting if the connection is in fact open before performing operations on the database.
It seems like using the app.locals would be the proper way to share the connection but I could not get that working either. Below is what I have at the moment. I've tried this many ways. Most of what I can find online seems to export the Mongo Node driver's method, not the connection itself. The idea is to connect once and never disconnect until the app shuts down.
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
async function connect () {
app.locals.dbConnected = false;
try {
await client.connect();
app.locals.dbConnected = true;
module.exports = client;
} catch (e) {
console.error(e);
}
};
then in another module do something like:
await client.db('syslogs').collection('production').insertOne(doc);
Is it possible to share the connection?
Could do something like below:
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
let __inst = null;
export default new Promise((resolve, reject) => {
if (__inst !== null) resolve(__inst);
// the open event is the key here
// like this we can handle error, close etc thru events as well
client.open((err, mongoInst) => {
if (err) reject(err);
__inst = mongoInst;
resolve(__inst);
});
});
Then in other module you can use the export client like you want.
Thanks.
I just got it working using app.locals.
index.js
const { MongoClient } = require("mongodb");
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
(async () => {
app.locals.dbConnected = false;
try {
await client.connect();
console.log("Connected to DB");
app.locals.client = client;
app.listen(PORT, HOST, () => {
console.log(`Running on http://${HOST}:${PORT}`);
});
} catch (e) {
console.error(e);
}
})();
Then in my module:
async function index (req, res) {
try {
let db = req.app.locals.client.db("admin");
await db.command({ ping: 1 });
console.log("pinged admin database");
}catch(err) {
console.log(err);
}
}

Redis giving error even after redis connected in nodejs

I have redis installed on my system and its running as well.
from node application, im using below code to work with redis.
redis.js
const redis = require("redis");
let client = redis.createClient(6379, '127.0.0.1', {});
let isRedis = false;
client.on("connect", function () {
console.log(`connected to redis`);
isRedis = true;
});
client.on("error", function (err) {
console.log("redis connection error " + err);
throw err;
});
client.on("end", function (err) {
console.log("redis connection end " + err);
});
module.exports = {
SetRedis,
GetKeys,
GetRedis,
GetKeyRedis,
delRedis
};
im using node index.js command to run the application which should also give me "connected to redis" when the connection is established, but i'm not getting this message on my console .
the npm package is also present in package.json
Node Redis 4.x doesn't allow you to pass in discrete arguments for the host and port. The canonical example of connecting to Redis with Node Redis is this:
import { createClient } from 'redis';
(async () => {
const client = createClient();
client.on('error', (err) => console.log('Redis Client Error', err));
await client.connect();
await client.set('key', 'value');
const value = await client.get('key');
})();
If you want to connect to somewhere other than localhost on port 6379, I recommend using a URL. Like this:
createClient({ url: 'redis://awesome.redis.server:6380' });
But if you want finer control, you can find all the gritty configuration options in the documentation on GitHub.
I guess you are making mistake while making connection.
It should have been
let client = redis.createClient('127.0.0.1', 6379, {});
rather than
let client = redis.createClient(6379, '127.0.0.1', {});
Working redis.js,
const redis = require("redis");
let isRedis = false;
(async () => {
let client = redis.createClient(6379, '127.0.0.1', {});// create config
client.on("connect", function () {
console.log(`connected to redis`);
isRedis = true;
});
client.on("error", function (err) {
console.log("redis connection error " + err);
throw err;
});
client.on("end", function (err) {
console.log("redis connection end " + err);
});
function GetKeyRedis(key) {
return new Promise(function (resolve, reject) {
console.log("dd----",key,isRedis);
if (isRedis) {
client.get(key).then((data,err) => {
if(err){
reject(err);
}
if(data){
resolve(data)
} else {
resolve(false);
}
});
} else {
resolve(false);
}
});
}
module.exports = {
GetKeyRedis
};
await client.connect();
})();

MongoDb how to cache MongoClient connection in NodeJs?

I am using MongoClient in NodeJs to carry out Db operations, I am running into connection and db caching issues, where the application shows the db connections are getting disconnected while doing db operations
Following are the errors -
MongoError: MongoClient must be connected before calling MongoClient.prototype.db
at MongoClient.db (/var/task/node_modules/mongodb/lib/mongo_client.js:313:11)
Error: Client network socket disconnected before secure TLS connection was established
at connResetException (internal/errors.js:609:14)
at TLSSocket.onConnectEnd (_tls_wrap.js:1557:19)
at Object.onceWrapper (events.js:420:28)
at TLSSocket.emit (events.js:326:22)
at TLSSocket.EventEmitter.emit (domain.js:483:12)
at endReadableNT (_stream_readable.js:1241:12)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
name: 'MongoNetworkError'
}
Unable to connect with the mongoDb : MongoError: Topology closed
at NativeTopology.close (/var/task/node_modules/mongodb/lib/core/sdam/topology.js:325:38)
at /var/task/node_modules/mongodb/lib/mongo_client.js:267:21
at maybePromise (/var/task/node_modules/mongodb/lib/utils.js:719:3)
at MongoClient.close (/var/task/node_modules/mongodb/lib/mongo_client.js:248:10)
Following is my DB connection and closing code-
I call the client method while going any db operation like findOne, insertOne, etc And closeDBConnection right before returning the API response.
import { MongoClient, Db } from "mongodb";
let cachedDb: Db = null;
let mongoClient: MongoClient = null;
export const client = async (): Promise<Db> => {
if (cachedDb && await mongoClient.isConnected()) {
console.info("cached db connection established");
return cachedDb;
}
mongoClient = new MongoClient('db URL here', {
useUnifiedTopology: true,
useNewUrlParser: true,
connectTimeoutMS: 90000,
poolSize: 10
});
try {
await mongoClient.connect();
if (await !mongoClient.isConnected()) {
await mongoClient.connect(err => {
if (err) {
console.error("Error : ", err);
throw new Error(`Unable to connect MongoDb Client, Reason: ${err}`
);
}
});
}
cachedDb = await mongoClient.db(await "DB name here");
console.info("db connection established");
return cachedDb;
} catch (error) {
console.error("Error in connecting to DB => ", error);
throw error;
}
};
export const closeDBConnection = async () => {
try {
if( mongoClient != null ){
await mongoClient.close();
mongoClient = null;
cachedDb = null;
console.log("db connection closed");
return true;
}
} catch (error) {
console.log("Error in closeDBConnection => ", error);
return false;
}
};
I've added connectTimeoutMS: 90000,poolSize: 10 to increase the default settings of 30000 and 5 respectively. Will it resolve the above errors?
What is the ideal way to cache a db connection in NodeJS on AWS Lambda?
Ref -
https://mongodb.github.io/node-mongodb-native/3.2/api/MongoClient.html

how to decouple mongodb atlas connection from the express server start

Im trying to decouple my express server start from the mongodb connection process .
mongodb.connect(process.env.CONNECTIONSTRING, { useNewUrlParser: true, useUnifiedTopology: true }, function (err, client) {
if (err) {
throw new Error(err)
}
module.exports = client
const server = require("./server")
server.start(opts, t => {
console.log(`server is up 4000`)
})
})
so instead of this single file I would like to have two files one used for mongodb connection , and other for starting the server . when i did this I got error related to mongodb, I think because the server started even before the mongodb conection was established.
any idea on how to solve this
Wrap it in a promise and call it wherever you want
Create a file name db.js it whatever else you want and require in the file that you need it. Then wrap the callback in a promise and export it for usage outside the file. Example above.
function initMongo() {
mongodb.connect(process.env.CONNECTIONSTRING, { useNewUrlParser: true, useUnifiedTopology: true }, function (err, client) {
return new Promise((resolve, reject) => {
if (err) {
return reject(err);
}
return resolve(client)
})
})
}
module.exports = { initMongo };
Then in your init function, you could call
const server = require("./server");
const mongoDb = require("./db");
async init() {
let client;
try {
client = await mongoDb.initMongo()
} catch(e) {
// could not connect to db
}
server.start(opts, t => {
console.log(`server is up 4000`)
})
}

Azure functions integration with Postgres in Node.js

I want to access to Azure Postgres DB from an Azure function.
Below is the node.js source code of Azure function.
module.exports = async function (context, req) {
try {
context.log('Start function!');
var pg = require('pg');
const config = {
host: 'taxiexample.postgres.database.azure.com',
user: 'postgres#taxiexample',
password: 'QscBjk10;',
database: 'taxi',
port: 5432,
ssl: false
};
var client = new pg.Client(config);
const query = 'insert into taxi values (\'2\');';
context.log(query);
client.connect();
var res = client.query(query);
await client.end();
context.log(res);
} catch (e) {
context.log(e);
} finally {
context.res = {
status: 200,
body: "ok"
};
}
};
The record doesn't insert, the res object returns the following error:
2020-03-04T23:03:59.804 [Information] Promise {
<rejected> Error: Connection terminated
at Connection.<anonymous> (D:\home\site\wwwroot\HttpTrigger1\node_modules\pg\lib\client.js:254:9)
at Object.onceWrapper (events.js:312:28)
at Connection.emit (events.js:228:7)
at Socket.<anonymous> (D:\home\site\wwwroot\HttpTrigger1\node_modules\pg\lib\connection.js:78:10)
at Socket.emit (events.js:223:5)
at TCP.<anonymous> (net.js:664:12)
}
2020-03-04T23:03:59.811 [Information] Executed 'Functions.HttpTrigger1' (Succeeded, Id=944dfb12-095d-4a28-a41d-555474b2b0ee)
Can you help me? Thanks
I've resolve it, it was a trivial programming error.
Below is the correct source code
module.exports = async function (context, req) {
try {
context.log('Start function!');
var pg = require('pg');
const config = {
host: 'example.postgres.database.azure.com',
user: 'postgres#example',
password: 'passwd;',
database: 'test',
port: 5432,
ssl: true
};
var client = new pg.Client(config);
const query = 'insert into test values (\'2\');';
context.log(query);
client.connect(err => {
if (err) {
console.error('connection error', err.stack);
} else {
console.log('connected');
client.query(query, (err, res) => {
if (err) throw err;
console.log(res);
client.end();
})
}
});
} catch (e) {
context.log(e);
} finally {
context.res = {
status: 200,
body: "ok"
};
}
};

Resources