create socket instance from vuex - sockets

I am using vue socket io for getting data from socket. For getting data I use query like
// ioinstance
import io from 'socket.io-client'
const restaurantId = localStorage.getItem('restaurant-id')
const socketUri = process.env.SOCKET_URI
export default io(socketUri, {
transports: ['websocket'],
query: `channel_id=restaurant-${restaurantId}`,
reconnect: true,
reconnectionDelay: 500,
reconnectionDelayMax: 1000,
pingInterval: 200
})
Here I get restaurantId after i successfully logged in to the panel and dispatch an action after successfully logged in like
// from vuex module
import VueSocketio from 'vue-socket.io-extended'
import ioInstance from '../../socket-instance'
...
...
socketInitialize ({dispatch}) {
let restaurantId = await localStorage.getItem('restaurant-id')
if (restaurantId && restaurantId != null) {
Vue.use(VueSocketio, ioInstance)
this._vm.$socket.on(`restaurant-${restaurantId}`, (data) => {
dispatch('socketIncoming', data)
})
}
}
but creating vue instance is not working from socketInitialize action although create instance from vue component is working fine
// from component
import Vue from 'vue'
import VueSocketio from 'vue-socket.io'
import ioInstance from './socket-instance'
...
...
mounted () {
let restaurantId = await localStorage.getItem('restaurant-id')
if (restaurantId && restaurantId != null) {
Vue.use(VueSocketio, ioInstance)
this.$socket.on(`restaurant-${restaurantId}`, (data) => {
this.$store.dispatch('socketIncoming', data)
})
}
}
Since I have to pass restaurantId for socket instance, I didn't initialize it from main.js (it renders first and restaurantId is not available here if not logged in) file. I need some suggestion, how could i create this initialization after logged in and any alternative way for initializing using Vue.use or this._vm or (new Vue()) or Vue.prototype

From Vue.use(plugin):
This method has to be called before calling new Vue()
So you have to register the plugin first then open the connection after when you ready. This question is already answered in FAQ section from the vue-socket.io-extended How to prevent connection until authed?.
Basically you have to tell socket.io to not open the connection at instantiate by set autoConnect to false:
const socket = io({
autoConnect: false
})
Then when you ready call open function:
this.$socket.io.opts.query = `channel_id=restaurant-${restaurantId}`
this.$socket.open()

Related

Insert a user by default in MongoDB in Nest JS (Only when the app starts)

I am changing the project from expressjs to nestjs.
In express, I added an admin user to the database by default in app.ts.
like this:
public async addDefaultAdmin() {
UserModel.find({ role: Roles.admin }).then(async (superAdmin) => {
if (superAdmin.length === 0) {
try {
const newUser = new UserModel({...});
await this.hashPassWord(newUser);
await newUser.save();
console.log("default admin successfully added.");
} catch (error: any) {
console.log(error);
}
}
});
}
I wanted to know how I can do this in NestJS?
Does NestJS or typeOrm have a solution for this issue?
You may need to use lifecycle events. NestJS fires events during application bootstrapping and shutdown.
According to doc, onApplicationBootstrap() event may be helpful in your case.
Called once all modules have been initialized, but before listening for connections.
However, NestJS does not expose a hook after the application starts listening, so in this case you need to run your custom function inside of bootstrap function right after the server could listen to a port.
The pseudocode would be like this:
// main.ts
import { User } from '/path/to/user.entity';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
...
await app.listen(3000);
let user = app.get(getRepositoryToken(User)); // You need to pass the entity file to typeorm
await addDefaultAdmin(user); // Pass the user model, and call the function
}
bootstrap();

How to connect to mongodb database using Nextjs?

Trying to connect to my mongodb database in the latest version of Nextjs. Things have changed so much, so I don't longer know what to do.
There's an example of how to set up the connection here: https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
They use this file:
//The mongodb.js file from the example
import { MongoClient } from 'mongodb'
const uri = process.env.MONGODB_URI
const options = {}
let client
let clientPromise
if (!process.env.MONGODB_URI) {
throw new Error('Please add your Mongo URI to .env.local')
}
if (process.env.NODE_ENV === 'development') {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options)
global._mongoClientPromise = client.connect()
}
clientPromise = global._mongoClientPromise
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options)
clientPromise = client.connect()
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise
However, they forgot to add how to actually use it. I can't even begin to figure it out.
//pages/api/user.js
import client from '/lib/mongodb.js'
export default async function handler(req, res) {
//How do I connect here?
}
And two bonus questions:
I used to do caching on my database connection. Is it not needed anymore?
What happened to the utils folder? It used to be special, in that it didn't send anything there to the client. Now everyone seem to use lib but I don't think there's anything special with it?
You can do like this:
const dbClient = await client;
const db = dbClient.db('db-name');
const collection = db.collection('collection-name');
// example to get a doc in collection
const doc = await collection.findOne({query:""}, {...options})

Why does Mongoose setClient return MongooseError: Must call `setClient()` with an instance of MongoClient?

I am having trouble getting setClient() to work. My understanding of this is, that I can make a connection to MongoDB with the native MongoDB MongoClient and then in another piece of code I should be able to use this instance of the MongoClient to connect to Mongoose. So set the client to Mongoose while using the same identical connection, not a separate one.
https://mongoosejs.com/docs/api/connection.html#connection_Connection-setClient
Set the MongoDB driver MongoClient instance that this connection uses to talk to MongoDB. This is useful if you already have a MongoClient instance, and want to reuse it.
Case A
import mongoose from 'mongoose';
import { MongoClient } from 'mongodb';
async function run() {
try {
const uri = 'mongodb://localhost:27017';
// Create a new MongoClient
const client = new MongoClient(uri);
const conn = mongoose.createConnection().setClient(client);
conn.getClient(); // MongoClient { ... }
conn.readyState; // 1, means 'CONNECTED'
} catch (error) {
console.log(error);
}
}
run();
This returns
MongooseError: Must call setClient() with an instance of MongoClient at NativeConnection.setClient (.../node_modules/mongoose/lib/connection.js:1391:11).
Why am I getting this error ? What is the correct code for setClient()?
Case B
Vercel shows how to used MongoDB and Mongoose in their environment exporting a clientPromise here with MongoDB https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/lib/mongodb.js and a dbConnect here with Mongoose https://github.com/vercel/next.js/blob/canary/examples/with-mongodb-mongoose/lib/dbConnect.js.
So given in db.js I have this exemplary code with the native MongoDB driver
import { MongoClient } from 'mongodb'
const uri = process.env.MONGODB_URI
const options = {}
let client
let clientPromise
if (!process.env.MONGODB_URI) {
throw new Error('Please add your Mongo URI to .env.local')
}
if (process.env.NODE_ENV === 'development') {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options)
global._mongoClientPromise = client.connect()
}
clientPromise = global._mongoClientPromise
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options)
clientPromise = client.connect()
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise
and in another file I like to use this clientPromise with Mongoose what do I do ?
Is my understanding correct here that I in fact can use the exported MongoDB clientPromise with Mongoose at all through the use of setClient() ? Or is setClient() used for something different ?
In another file, if I try this
import mongoose from 'mongoose';
import clientPromise from '$lib/mongodb';
export async function get() {
try {
const client = await clientPromise;
console.log(client); // logs client just fine
const conn = mongoose.createConnection().setClient(client);
// starts complaining here with
// MongooseError: Must call `setClient()` with an instance of MongoClient
conn.getClient(); // MongoClient { ... }
conn.readyState; // 1, means 'CONNECTED'
console.log(conn);
return {
status: 200,
body: {
message: 'ok'
}
};
} catch (error) {
console.log(error);
}
}
the same error is shown.
How do I get setClient() to work on either, the MongoClient instance or the clientPromise?
edit:
I also get this error.
Argument of type 'import(".../node_modules/mongodb/mongodb").MongoClient' is not assignable to parameter of type 'import(".../node_modules/mongoose/node_modules/mongodb/mongodb").MongoClient'.
The types of 'options.credentials' are incompatible between these types.
Type 'import(".../node_modules/mongodb/mongodb").MongoCredentials' is not assignable to type 'import(".../node_modules/mongoose/node_modules/mongodb/mongodb").MongoCredentials'.

SvelteKit With MongoDB ReferenceError: global is not defined

I'm trying to setup MongoDB connection library function. I know this function is solid, its used in a whole lot of places (search for Global is used here to maintain a cached connection across hot reloads) and you'll find a whole lot of uses including next.js releases. Note, the purpose of global storage for the database connection is to reduce the overall # of db connections in use at any one time.
What I'm not understanding is the error I'm getting when I import this library via import { connectToDatabase } from '$lib/database';
database.js
// https://github.com/mongodb-developer/mongodb-next-todo/blob/main/util/mongodb.js
import { ENV_OBJ } from "$lib/env";
import { MongoClient } from "mongodb";
const uri = ENV_OBJ.MONGODB_URI;
if (!uri) {
throw new Error("Please define the Mongodb uri environment variable inside .env");
}
/**
* Global is used here to maintain a cached connection across hot reloads
* in development. This prevents connections growing exponentially
* during API Route usage.
*/
let cached = global.mongo
if (!cached) {
cached = global.mongo = { conn: null, promise: null }
}
export const connectToDatabase = async() => {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const options = {
useNewUrlParser: true,
useUnifiedTopology: true
};
cached.promise = MongoClient.connect(MONGODB_URI, opts).then((client) => {
return {
client,
db: client.db(MONGODB_DB),
}
})
}
cached.conn = await cached.promise;
return cached.conn;
}
The errors:
global is not defined
ReferenceError: global is not defined
at node_modules/mongodb/lib/promise_provider.js (http://localhost:3000/node_modules/.vite/mongodb.js?v=3885e04e:548:25)
at __require2 (http://localhost:3000/node_modules/.vite/chunk-6ODJH7E3.js?v=3885e04e:10:44)
at node_modules/mongodb/lib/utils.js (http://localhost:3000/node_modules/.vite/mongodb.js?v=3885e04e:6524:30)
at __require2 (http://localhost:3000/node_modules/.vite/chunk-6ODJH7E3.js?v=3885e04e:10:44)
at node_modules/mongodb/lib/cursor/abstract_cursor.js (http://localhost:3000/node_modules/.vite/mongodb.js?v=3885e04e:10873:19)
at __require2 (http://localhost:3000/node_modules/.vite/chunk-6ODJH7E3.js?v=3885e04e:10:44)
at node_modules/mongodb/lib/index.js (http://localhost:3000/node_modules/.vite/mongodb.js?v=3885e04e:25281:29)
at __require2 (http://localhost:3000/node_modules/.vite/chunk-6ODJH7E3.js?v=3885e04e:10:44)
at http://localhost:3000/node_modules/.vite/mongodb.js?v=3885e04e:25616:23
Note, I do see a file in my generated minimal sveltekit repo called global.d.ts I'm not sure of its purpose. It contains only:
/// <reference types="#sveltejs/kit" />
Any ideas on what's causing the error?
Reference: "#sveltejs/kit": "version": "1.0.0-next.118",
Edit: After spending a whole lot of time on this issue, the global not defined error seems to come from import { MongoClient } from "mongodb"; If I add appropriate console.logs, I can see that the MongoClient function works fine on the server, but then I get the global error on the client. The server indicates no errors at all.
So it turns out I was calling import { connectToDatabase } from '$lib/database' not in a .js helper file or api style (.js) endpoints. I was attempting to use that import and make a database call directly from the <script> portion of a xxx.svelte file.
Definite no go. That generates an immediate global not defined error.

Editing My HTTP Call to Use Sockets (socket.io) to Receive Data via an Observable in my Angular 2 App

Right now I have an http get call handling data coming from an api into my Angular 2 app. Now we're switching to using sockets via socket.io. I have been using an observable to get the data, and I know I can continue to do that while using socket.io sockets. But I'm having difficulty figuring out exactly what it should look like - i.e., how I need to edit my getByCategory function call to receive the data via a socket connection. This is what my getByCategory function currently looks like in my client-side Angular service:
private _url: string = 'https://api.someurl';
getByCategory() {
return this._http.get(this._url)
.map((response:Response) => response.json())
.catch(this._errorsHandler);
}
_errorsHandler(error: Response) {
console.error(error);
return Observable.throw(error || "Server Error");
}
And, on the server side, this is what my function export looks like in our mongoDB setup (already set up to use sockets via socket.io):
exports.getByCategory = function(req, res, next) {
let skip, limit, stage, ioOnly = false;
let role='office_default';
if (_.isUndefined(req.params)) {
stage = req.stage;
skip = parseInt(req.skip) || 0;
limit = parseInt(req.limit) || 0;
role = req.role;
ioOnly=true;
}
else {
stage = req.params.stage;
skip = parseInt(req.query.skip) || 0;
limit = parseInt(req.query.limit) || 0;
role = req.query.role;
}
console.log(role);
Category[role].find({'services.workflow.status': stage}).skip(skip).limit(limit).exec(function(err, doc) {
if (err) { if (!ioOnly) { return next(err) } else { return res(err)}}
else if(doc) ((!ioOnly) ? res.json(doc) : res(doc));
else ((!ioOnly) ? res.sendStatus(204) : res(doc));
});
};
How should I edit my getByCategory function to use socket.io instead of http in my service? Do I need an emit function coming from my api to act on in my Angular 2 service - or can I just adjust my current getByCategory function to use sockets within the existing observable instead?
I thought about editing the function to look something like this:
getByStage() {
this.socket.on('getByCategory')
.map((response:Response) => response.json())
.catch(this._errorsHandler);
}
}
... but to do that I'd need the server function export to make it available via an "emit" or something similar, wouldn't I? Would it work if I did that? Am I missing something here?
If you need to work with socket connection (like socket.io), you should depend on callbacks.
So, you should set up callback functions to work with them.
A demo is given here-
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import * as io from 'socket.io-client';
export class ChatService {
private url = 'http://localhost:5000';
private socket;
sendMessage(message){
this.socket.emit('add-message', message);
}
getMessages() {
let observable = new Observable(observer => {
this.socket = io(this.url);
this.socket.on('message', (data) => {
observer.next(data);
});
return () => {
this.socket.disconnect();
};
})
return observable;
}
}
A complete tutorial of using Angular2 with socket.io is given here.
Hope you have your answer.