Clean way to "require" in nodejs when having to pass params - javascript

I got files called socket.js and Chat.js.
Let's say Chat.js contains:
function Chat(io, socket) {
this.sendChatMessage(data) {};
}
module.exports = Chat;
And socket.js
module.exports = function (io) {
io.on('connection', function(socket) {
var Chat = new (require('./Chat'))(io, socket),
});
}
After several tries, the above is the cleanliest way of requiring "Chat" that I've found, but it still looks weird for something so frequently used.
I tried stuff like (still clean I guess)
var Chat = require('./Chat'),
Chat = new Chat(io, socket);
Also tried adding the "new" in module.exports = new Chat; directly etc. etc.
Is there any standard for this? If not, what do you use?

Yup, that's how you do it: export whatever function(s) you need and call them after requiring the module.
Also tried adding the "new" in module.exports = new Chat
Don't do that unless you really want to export an instance and not the constructor.
It's pretty common to use a pattern like this so you could omit the new where you call the constructor:
function Chat(io, socket) {
if (! (this instanceof Chat)) return new Chat(io, socket);
this.sendChatMessage(data) {};
}
var Chat = require('./Chat')(io, socket)

I'm not sure what is most popular now but here is how I might do it with babel and the ES6 standard:
// chat.js
export default class Chat {
constructor(io, socket) {
this.io = io;
this.socket = socket;
this.sendMessage(data);
}
sendMessage(data) {
//
}
}
// iochat.js
import Chat from './chat';
export default function connectChat (io) {
io.on('connection', (socket) => {
let chat = new Chat(io, socket);
});
}
// tio.js
import connectChat from './iochat';
let io = { on:()=>{}};
connectChat(io);
Although I am guessing the connectChat thing is part of a larger module or app.

Related

NodeJS: Controlling the order of loading modules

Here is the scenario:
I have 3 files (modules):
app.js
(async () => {
await connectoDB();
let newRec = new userModel({
...someprops
});
await newRec.save();
})();
The app.ts is the entry point of the project.
database.ts
interface ConnectionInterface {
[name: string]: mongoose.Connection;
}
export class Connection {
public static connections: ConnectionInterface;
public static async setConnection(name: string, connection: mongoose.Connection) {
Connection.connections = {
...Connection.connections,
[name]: connection,
};
}
}
export async function connectToDB() {
const conn = await mongoose.createConnection('somePath');
await Connection.setConnection('report', conn);
}
model.ts
const userSchema = new mongoose.Schema(
{
..someprops
},
);
const userModel = Connection.connections.report.model('User', userSchema);
export default userModel;
What I am trying to do: I need to have multiple mongoose connections, so I use an static prop called connections in Connection class (in database.ts); every time that I connect to a database I use setConnection to store the connection in mentioned static prop, so I can access it from every module in my project by its name which is report in this case.
Later, In model.ts I use Connection.connections.report to access the connection report to load my model!
Then, When I run app.ts I get the following error which is logical:
const aggregationModel = Connection.connections.report.model('User', userSchema)
^
TypeError: Cannot read property 'report' of undefined
The reason that causes this (I think) is, while loading imported modules in app.ts, .report is not declared because the app.ts isn't run completely (connectoDB() defines the .report key).
The codes that I have mentioned have been simplified for preventing complexity. The original app is an express app!
Now, How should I solve this error?
Thanks in advance.
You can wait for the connection to finish before using it if you change up your class slightly.
const connection = await Connection.getConnection()
const model = connection.example
...
class Connection {
...
public static async getConnection() => {
if (!Connection.connection) {
await Connection.setConnection()
}
return Connection.connection
}
}

node Mqtt.js structuring code / best practices

So I've been searching for a long time on mqtt.js examples for structuring and best practices and haven't found anything worthwhile. thus [main] how do you structure your mqtt.js code in your node/express application?
[1] So the libraries mqttjs/async-MQTT provides some example on connecting and on-message but on a real app with lots of subscription and publishes how to structure code so that it initiliazes on the app.js and uses the same client (return from the mqtt.connect) for all the sub/pub in different files.
[2] and from the question[1] should my app only use 1 client for all the works or can use multiple clients as needed on multiple files (let's say I have 3 files mqttInit, subscriber, publisher. so if I use the init on subscriber and get a client should I export it or just make a new instance of a client on the publisher file)
[3] so the mqttjs API provides only an onMessage function so all subscribed topics message gets here thus I put a switch or a if else to manage this so if we have a lot of topics how do you manage this
[4] so my current setup is kind of messed up
this is the initializer file lets say'
mqttService.js
const mqtt = require("mqtt");
const { readFileSync } = require("fs");
module.exports = class mqttService {
constructor() {
this.client = mqtt.connect("mqtt://xxxxxxxxxxx", {
cert: readFileSync(process.cwd() + "/certificates/client.crt"),
key: readFileSync(process.cwd() + "/certificates/client.key"),
rejectUnauthorized: false,
});
this.client.on("error", (err) => {
console.log(err);
});
this.client.once("connect", () => {
console.log("connected to MQTT server");
});
}
};
subscriber.js
this is the function(subscribe()) that I call in app.js to init the mqtt thing
const { sendDeviceStatus, sendSensorStatus } = require("../socketApi");
const { client } = new (require("./mqttService"))();
function subscribe() {
let state = {
timer: false,
};
...
let topics = {
....
},
client.subscribe([...]);
client.on("message", async (topic, buffer) => {
if (topic) {
...
}
});
}
module.exports = {
subscribe,
client,
};
publish.js
const { AsyncClient } = require("async-mqtt");
const _client = require("./subscribe").client;
const client = new AsyncClient(_client);
async function sendSensorList(daqId) {
let returnVal = await client.publish(
`${daqId}-GSL-DFC`,
JSON.stringify(publishObject),
{ qos: 1 }
);
console.log(returnVal);
return publishObject;
}
.....
module.exports = {
sendSensorList,
.......
};
so as you can see from the above code everything is kind of linked with one another and messed up thus I need some expo on how you structure code
thanks for reading, please feel free to provide any info and any info is much appreciated

How to add side effect to creating new record in Strapi by customizing controller?

I am trying to trigger a side effect (send notification, using socket.io) when adding new record in Strapi. The socket setup is OK, successfully emitting from back-end (Strapi API) to front-end.
I followed the docs on customizing controllers and the recommendations in this Stack Overflow thread, but didn't help. Nothing happens when changing the controller - tried to break it by replacing the create function body with just return null; or console.log(), but still nothing. Here's the ../controllers/Orders.js:
'use strict';
const { parseMultipartData, sanitizeEntity } = require('strapi-utils');
module.exports = {
async create(ctx) {
let entity;
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
entity = await strapi.api.order.services.order.create(data, { files });
} else {
entity = await strapi.api.order.services.order.create(ctx.request.body);
}
strapi.emitToAllUsers(entity);
return sanitizeEntity(entity, { model: strapi.query('order').model });
},
};
strapi.emitToAllUsers() is defined in bootstrap.js. Connection ready messages and other emitted data is received in the front end, but stuff inside the controller seems to not be invoked at all. Here's the boilerplate stuff from bootstrap.js:
'use strict';
require('dotenv').config({ path: require('find-config')('.env') });
module.exports = () => {
var io = require('socket.io')(strapi.server);
var users = [];
io.on('connection', socket => {
socket.user_id = (Math.random() * 100000000000000); // not so secure
users.push(socket); // save the socket to use it later
socket.on('disconnect', () => {
users.forEach((user, i) => {
// delete saved user when they disconnect
if (user.user_id === socket.user_id) {
users.splice(i, 1);
}
});
});
io.emit('emit_test');
});
strapi.io = io;
// send to all users connected
strapi.emitToAllUsers = (order) => {
io.emit('new_order', order);
};
};
API controllers ./api/blabla/controllers/Blabla.js are only called by your REST API. To make sure the Admin panel will work in any circumstances, the Content Manager plugin uses it's own functions. If you want to apply so things to both REST API and Admin panel, you will have to customize the life cycle functions. But you will have less flexibility because of some issues you will be able to find in this thread https://github.com/strapi/strapi/issues/1443
Source: Strapi
You have to do it from the lifecycle object in the model not from the controller, controller checks only the api layer, model checks the database/strapi layer
https://strapi.io/documentation/v3.x/concepts/models.html#concept
module.exports = {
lifecycles: {
afterCreate: async (result, data) => {
// after create registry from strapi admin
strapi.emitToAllUsers(result);
}
}
}

Export logging in Nodejs between files

I have two files in nodejs :
index.js
function.js
The index.js is my main file in which i call the functions inside function.js. In function.js i need to use logging, the problem is i didn't figure out how to use it.
function.js
module.exports = {
Exemplfunciton: async () => {
app.log('#### This is just an exemple im trying to run')
}
checkCalcul:async(a,b) = > {
log.(`The Val of A : ${a}, the Val of B: ${b}`
return a+b
}
}
index.js
const functionToCall = require('/function.js)
module.exports = app => {
functionToCall.Exemplfunciton()
functionToCall.checkCalcul(4,5)
}
Will return
app is not defined
tried it without the app in the function.js it returned to me
log not defined.
I only need to use the app.log between the functions ( my main one the index.js and the function.js )
Pass as an argument
module.exports = app => {
functionToCall.Exemplfunciton(app) // add here
}
Then consume
module.exports = {
Exemplfunciton: async (app) => { // add here
app.log('#### This is just an exemple im trying to run')
}
}
To log in Node.js, you should use console https://nodejs.org/api/console.html
Example
module.exports = {
ExampleFunction: async () => {
console.log('#### This is just an example I\'m trying to run')
}
}
const functionToCall = require('./function.js')
functionToCall.ExampleFunction() // logs #### This is just an example I\'m trying to run
Consider extracting the log functionality out into its own file that can be referenced by function.js, index.js, and anything else in your app. For example:
logger.js
module.exports = {
log: function() {
/* aggregate logs and send to your logging service, like TrackJS.com */
}
}
function.js
var logger = require(“./log.js”);d
module.exports = {
exampleFunction: function() {
logger.log(“foo bar”);
}
};
index.js
var functions = require(“./functions.js”);
var logger = require(“./log.js”);
functions.exampleFunction();
logger.log(“foo”);
You should send the logs off to a service like TrackJS to aggregate, report, and alert you to production problems.

How can I access methods inside a class from outside of class

I have a couple questions regarding Class files. I have the below Class
class CouchController {
constructor(couchbase, config) {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
doSomeQuery(queryString, callback) {
this.bucket.manager().createPrimaryIndex(function() {
this.bucket.query(
this.N1qlQuery.fromString("SELECT * FROM bucketname WHERE $1 in interests LIMIT 1"),
[queryString],
callback(err, result)
)
});
}
}
my problem is how can I go and access the doSomeQuery function from outside the class file? Inside there is no issue accessing the function but I need to be able to call it from outside.
I tried something like this
const CouchController = require("../controllers/CouchController")(couchbase, config)
let newTest = new CouchController
doing so newTest never exposes the doSomeQuery method.
Also what are the limitations of a method ? Can it only be a simple one or can it be async and use promises etc ?
There are 2 main things that you should consider with the following problem.
Export it properly first. I'm not sure if you meant to leave this out, but it's important to export the class for use outside as a require. Here is the NodeJS exports documentation if you wish for the technical details.
// common module default export
module.exports = class CouchController {
constructor(couchbase, config) {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
doSomeQuery(queryString, callback) {
this.bucket.manager().createPrimaryIndex(function() {
this.bucket.query(
this.N1qlQuery.fromString("SELECT * FROM bucketname WHERE $1 in interests LIMIT 1"),
[queryString],
callback(err, result)
)
});
}
}
The class initialization is slightly incorrect. You can see the docs on this here. You can change your require and initialization to...
const CouchController = require('../controllers/CouchController');
const newTest = new CouchController(couchbase, config);
// now you can access the function :)
newTest.doSomeQuery("query it up", () => {
// here is your callback
})
If you were using ES6 modules or typescript you could export something like...
export default class CouchController {
// ...
}
... and import something like...
import CouchController from '../controllers/CouchController';
const newTest = new CouchController(couchbase, config);
You need to instantiate the class after importing it
Change the following
const CouchController = require("../controllers/CouchController")(couchbase, config)
let newTest = new CouchController
to
const CouchController = require("../controllers/CouchController")
let newTest = new CouchController(couchbase, config)
Also you need to export your class like this
export default class CouchController {
and then access method like this
newTest.doSomeQuery(...)
I figured it out after some forth and back, part of my problem was the fact that for some reason visual studio code did not show me the method which threw me off. Manually typing made it ultimately avail.
Here is my Class and i actually moved the config and couchbase itself into the class file so no need to pass it anymore.
const couchbase = require("couchbase")
const config = require("../config/config")
class CouchController {
constructor() {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = this.cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
getDoc2(docID){
return new Promise((resolve,reject)=>{
this.bucket.get(docID ,(err, result)=>{
if(err) return reject(err);
return resolve({docID,result});
});
});
}
}
module.exports = CouchController
And here is how i call my Class now and connect to the backend to fetch my data.
const CouchController = require("./controllers/CouchController")
let newTest = new CouchController
const test= async()=>{
let { docID, result } = await newTest.getDoc2("grid_info::20b05192-79e9-4e9d-94c9-91a4fc0a2765")
console.log(docID)
console.log(result)
}

Categories