unable to connect socket user in http request - javascript

I was trying to send message to all the connected socket user
after making a post request to xyz route.
but it does work fine when i execute the entire process in websocket request
for example SubscribeMessage('newMsg') is working fine and all the connected user who are listening to onMessage are getting my message
but when i try to make http request to xyz route connect socket user who are listening onMessage does not get any message.
import {
Body,
ConflictException,
Controller,
Get,
HttpStatus,
OnModuleInit,
Patch,
Post,
Request,
UseGuards
}
from '#nestjs/common'
import {
MessageBody,
WebSocketGateway,
WebSocketServer
}
from '#nestjs/websockets'
import { Server } from 'socket.io'
#WebSocketGateway()
#Controller('xyz')
export class xyz implements OnModuleInit {
constructor(private readonly daoService: xyzService) {
this.server = new Server()
}
private clients: any = []
#WebSocketServer()
server: Server
onModuleInit() {
this.server.on('connection', (socket) => {
console.log(socket.id)
this.clients.push(socket)
})
}
#Post('xyz)
private async deployGovernanceToken(
#Request() req,
#Body() governanceTokenDto: GovernanceTokenDto
) {
this.clients.forEach((client) => {
console.log('client', client)
client.emit('onMessage', {
msg: 'New Message',
content: 'hi'
})
})
return this.clients.length
}
#SubscribeMessage('newMsg')
onnewMsg(#MessageBody() body: any) {
console.log(body)
this.server.emit('onMessage', {
msg: 'New Message',
content: body
})
}

Related

Angular Node | SocketIO | Event not emitted from node

I had asked this question before but here's a simple code for the same.
Im sending the data to Node from angular via websocket but I don't get the emitted event:
I've followed 10+ tutorials and forums, newest from here: https://www.youtube.com/watch?v=66T2A2dvplY&t=317s
service:
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { io } from 'socket.io-client';
#Injectable({
providedIn: 'root'
})
export class SocketService {
socket = io('ws://localhost:3000'); // adding 'http://localhost:3000' also doesnt work
constructor() {}
listen(eventName: string) {
return new Observable( subscriber => {
this.socket.on(eventName, data => {
subscriber.next(data);
});
});
}
emit(eventName: string, data) {
this.socket.emit(eventName, data);
}
}
from component's ngOnInit(), this is called:
this._socketService.listen('test event').subscribe( data => {
console.log("data from server: ", data);
});
server code of Node:
const app = require('./app');
const port = process.env.PORT || 3000;
const server = require('http').createServer(app);
const socketio = require('socket.io');
const io = socketio(server,
{
serveClient: true,
pingInterval: 60000,
pingTimeout: 60000000,
cors: {
origin: "http://localhost:4200",
methods: ["GET", "POST"],
credentials: true
}
});
io.on('connection', function (socket) {
console.log("A user connected ", socket.connected); // works till here for every ping interval
socket.emit('test event', 'here is some data'); // this is either not executed or doesn't work
});
server.listen(port);
socket.connected is always true in NODE server, but false in Angular
What Ive tried:
CORS has been suppressed, I hope that's not the issue cuz nothing is seen like so
changing io.('connection' ...) to io.connect('connect'...)
init this.socket = io(...) in constructor
There is no data exchange seen in Network or Network > WS tab in case I emit from Angular too
This is my 3rd day with this problem, I'll highly appreciate any help.
Thank you
your mixing protocols from client.
change
socket = io('ws://localhost:3000');
to
socket = io('http://localhost:3000', { withCredentials: true });
As mentioned in introduction under chapter What Socket.IO is not that socket.io is not a pure WS lib.

Socket IO + React - 'Welcome message

I'm planning on adding a 'Welcome' message to all users that join a chat. I can't seem to get it to work.
Server Side:
socket.emit('welcome', { message: 'Welcome!' });
client side in the useEffect hook:
socket.on('welcome', function(data) {
welcomeMessage(data.message)
})
function welcomeMessage(message) {
messages([message]);
}

Implement unread messages

I am implementing a live chat.
Here is my server file.
io.on('connection', socket => {
socket.on('userConnect', async (room, user_id) => {
socket.join(room);
});
socket.on('send-chat-message', (room, sender_id, userMessage) => {
const message = new Message(room, sender_id, userMessage);
db.query(message.saveMessage());
socket.to(room).emit('chat-message', { message: userMessage, user: sender_id });
});
});
This is how I implemented the connection to the room and the connection for sending messages from the client.
How can I make a function that the user has not yet read the message?

Angular 5 http post method not called in nodejs

I have a nodejs as Backend Service and angular 5 as front end, I want to call a POST method to NodeJS Server, send a Blob File to server.
But that post method is executed, and nothing shown on backend console log.
Here are some code piece:
server.js
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const bodyParser = require('body-parser');
const cors = require('cors');
app.use(cors());
//create a cors middleware
app.use(function (req, res, next) {
//set headers to allow cross origin request.
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.post('/decrypt', function (req, res) {
console.log("decrypt called");
return 'data back';
})
And in AngularJS:
database.services.ts:
import { Injectable, Input } from '#angular/core';
import { Http, Response, ResponseContentType } from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import { Observable } from 'rxjs/Observable';
import { saveAs, FileSaver } from 'file-saver/FileSaver';
import { HttpClientModule, HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
#Injectable()
export class DatabaseService {
private API_GET_LIST_FILES = 'http://localhost:3000/files';
private BASE_URL = 'http://localhost:3000/';
private API_GET_FILE = 'http://localhost:3000/download?name=';
constructor(private http: Http) { }
getFile(key: string) {
return this.http.get(this.API_GET_FILE + key, {
responseType: ResponseContentType.Blob
})
.map(res => {
return {
filename: key.split('/').pop(),
data: res.blob()
};
})
.subscribe(res => {
this.decryptFile(res.data);
saveAs(res.data, res.filename);
}, error => {
console.log('download error:', JSON.stringify(error));
}, () => {
console.log('Completed file download.');
})
}
decryptFile(data: any): Observable<any> {
const httpOptions = {
Headers: new HttpHeaders({
'Content-Type': 'application/octet-stream',
'data': data
})
};
console.log(data, typeof data, this.BASE_URL + `decrypt`);
return this.http.post(`http://localhost:3000/decrypt`, httpOptions);
}
}
This getFile function will be called once I click the file download button on page, because in the browser console, it will print out the Blob(564534) {size: 564534, type: "application/octet-stream"} "object" "http://localhost:3000/decrypt"
I want the nodejs Server to take this post method and the Blob (GPG file) object as a parameter, and do something.
But looks like the backend server didn't print out anything.
Please advise how to modify this code, should I use POST or PUT? I want to pass a GPG file to nodeJS server and decrypt it.
Thanks,
decryptFile returns Observable, you must subscribe to it to execute the http call:
this.decryptFile(res.data).subscribe(decrypted => {???});
Edit: Could not resist, a few observations, feel free to ignore:
Why do you get a file from server and then send it back there? Why don't you just decrypt the file during the first API call and return that?
From security point of view... nevermind, I just hope there will be some authorization on the server as you are dealing with PGP files...
You should preferably start using HttpClient from #angular/common/http instead of Http. Good news is you have that imported already.
Depending on the size of the files you might want to consider using http upload instead of POST. Still, see the first point.

Error connecting Ember client side to Node/ Mongo backend

I am building a web app that uses Ember for the client side and Node for the server side. The database I am using is Mongo. Everything is working on the server side (I am able to use Postman to GET, POST, PUT, and DELETE users. I think I almost have everything hooked up on the client side, but Ember is throwing me one final error when I navigate to the /users route:
ember.debug.js:28535 Error while processing route: users Assertion Failed: You must include an 'id' for user in an object passed to 'push' Error: Assertion Failed: You must include an 'id' for user in an object passed to 'push'
Any ideas why this is happening/ how to fix it?
Here are the relevant parts of my server.js file:
var User = require('./models/user');
// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Add CORS headers
app.use(function (request, response, next) {
response.header("Access-Control-Allow-Origin", "http://localhost:4200");
response.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.header("Access-Control-Allow-Resource", "*");
response.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
next();
});
var port = process.env.PORT || 8080; // set our port
// ROUTES FOR OUR API
var router = express.Router(); // get an instance of the express Router
// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(request, response) {
response.json({ message: 'hooray! welcome to our api!' });
});
// more routes for our API will happen here
// REGISTER OUR ROUTES
// all of our routes will be prefixed with /api/v1
app.use('/api/v1/', router);
// START THE SERVER
app.listen(port);
console.log('Magic happens on port ' + port);
// more routes for our API will happen here
// on routes that end in /users
// ----------------------------------------------------
router.route('/users')
// create a user (accessed at POST http://localhost:8080/api/v1/users)
.post(function(request, response) {
var user = new User(); // create a new instance of the User model
user.name = request.body.name; // set the user's name (comes from the request)
user.email = request.body.email; // set the users's email property
user.password = request.body.password; //set the user's password property
// save the user and check for errors
user.save(function(error) {
if (error)
response.send(error);
response.json({ message: 'User created!' });
});
})
// get all the users (accessed at GET http://localhost:8080/api/v1/users)
.get(function (request, response) {
User.find(function (error, users) {
if (error) response.send(error);
response.json(users);
});
});
// on routes that end in /users/:user_id
// ----------------------------------------------------
router.route('/users/:user_id')
// get the user with that id (accessed at GET http://localhost:8080/api/users/:user_id)
.get(function (request, response) {
User.findById(request.params.user_id, function (error, user) {
if (error) response.send(error);
response.json(user);
});
})
// update the user with this id (accessed at PUT http://localhost:8080/api/users/:user_id)
.put(function (request, response) {
// use our user model to find the user we want
User.findById(request.params.user_id, function(error, user) {
if (error) response.send(error);
// update the user info
user.name = request.body.name;
user.email = request.body.email;
user.password = request.body.password;
// save the user
user.save(function(error) {
if (error) response.send(error);
response.json({ message: 'User updated!' });
});
});
})
// delete the user with this id (accessed at DELETE http://localhost:8080/api/users/:user_id)
.delete(function (request, response) {
User.remove({
_id: request.params.user_id
}, function(error, user) {
if (error) res.send(err);
response.json({ message: 'Successfully deleted' });
});
});
Here is my application adapter (on the Ember side):
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
host: 'http://localhost:8080',
namespace: 'api/v1'
});
Here is my serializer (on the Ember side):
import JSONAPISerializer from 'ember-data/serializers/json-api';
import DS from 'ember-data';
export default JSONAPISerializer.extend({
primaryKey: '_id'
});
export default DS.JSONSerializer;
Here is my model (on the Ember side):
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
export default Model.extend({
name: attr('string'),
email: attr('string'),
password: attr('string')
});
Here is my users.js route (on the Ember side):
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findAll('user');
},
actions: {
createUser(newName, newEmail, newPassword) {
this.store.createRecord('user', {
name: newName,
email: newEmail,
password: newPassword
}).save();
},
updateUser(user) {
user.save();
},
deleteUser(user) {
user.destroyRecord();
}
}
});
From your posted code your Application adapter is defined as RESTAdapter and your serializer is defined as JSONAPISerializer. Ember will expect JSON API format as defined on jsonapi ORG site
To solve you can do two things. Make node output JSON api format with data id and attributes format using this library for example: https://github.com/SeyZ/jsonapi-serializer or just make sure that you use REST serializer and adapter for your resources.
Try to define your application serializer like this
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
primaryKey: '_id',
serializeId: function(id) {
return id.toString();
}
});
Make sure that JSON output include something like this:
{
users: [
{"_id": "13ac3f0d4e29d794d9f62898","name":"", "email": "" },
{"_id": "13ac3f0d4e29d794d9f62899","name":"", "email": "" }
]
}
Another small issue is that your API endpoint on server side that creates, deletes or updates the user returns message instead of the users resource
user.save(function(error) {
if (error) response.send(error);
response.json({ message: 'User updated!' });
});
You should always return the updated resource, in this case you need to return the user as you do in GET /users/ID route with proper status and error code, for example:
When creating a user ember would expect that you return 201 CREATED status code and json response of user resource. For DELETE and PATCH/PUT (Update) you need to return status code 200. In all cases you need to use response.json(user) instead of outputting messages.
If you are not able to process the request (for example when creating a user email is already taken) you should respond with 422 and return proper error message. See this for handling errors: http://emberjs.com/api/data/classes/DS.Errors.html
Hope it helps.

Categories