Angular2 CLI Socket.io Cannot read property 'on' undefined - node.js

I want to use socket.io module for sending message and I am newbie in using it. I am trying to run socket.io within my Angular2 CLI + Node.js application and I am getting following error:
TypeError: Cannot read property 'on' of undefined
at MessagesComponent.webpackJsonp.363.MessagesComponent.sendMessage
(messages.component.ts:34)
What is wrong with my code and how can I connect and send message to the socket.io server?
messages.component.html
<div class="stick" style="background-color:#F5F5F5;">
<h5>Messages:</h5>
<ul>
<li *ngFor="let msg of msgs">
{{msg}}
</li>
</ul>
<input #mm/>
<button (click)="sendMessage(mm.value); mm.value=''">Send</button>
</div>
messages.component.ts
import { Component,Input,OnInit,Output,EventEmitter,HostListener,ElementRef, NgZone} from "#angular/core";
import * as sio from 'socket.io-client';
import { Observable } from 'rxjs/Observable';
#Component({
selector: "messages",
templateUrl: './messages.component.html'
})
export class MessagesComponent implements OnInit{
socket: SocketIOClient.Socket;
private url = 'http://localhost:4200';
constructor(private _zone: NgZone, public http: Http) {}
ngOnInit() {
}
sendMessage(message){
this.socket.on('connect', function(data) {
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;
}
}
www.ts
import { app } from '../app';
import * as http from 'http';
/**
* Get port from environment and store in Express.
*/
const port = normalizePort(process.env.PORT || 3000);
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
let io = require('socket.io').listen(server);
io.on('connection', (socket) => {
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('add-message', (message) => {
io.emit('message', {type:'new-message', text: message});
});
});
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
Solution:
constructor(private _zone: NgZone, public http: Http) {
this.socket = sio(this.url);
}
in your on callback use arrow function to preserve this keyword :
sendMessage(message){
this.socket.on('connect', (data) => {
this.socket.emit('add-message', message);
});
}

you have to instantiate your socket :
constructor(private _zone: NgZone, public http: Http) {
this.socket = sio(this.url);
}
in your on callback use arrow function to preserve this keyword :
sendMessage(message){
this.socket.on('connect', (data) => {
this.socket.emit('add-message', message);
});
}

Related

Web socket wss connection failed having secure web server in Node and Angular

I am trying to connect a secure websocket connection from client (angular app) with my server (nodejs). I used mkcert to generate my key and cert and server is running in https showing connection is secure. when I am trying to connect with WS, the webscoet connects with server but when I use WSS I am getting an error of WebSocket connection to 'wss://localhost:port/' failed. Can anyone let me know where am I getting wrong to connect wss or how to connect wss websocket connection here?
My client side code is
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(){
connectToServer();
}
title = 'SSL-WEB-SOCKET-CLIENT';
}
function connectToServer() {
let ws= new WebSocket("wss://localhost:8082/");
ws.addEventListener("open", ()=>{
console.log("We are connected");
ws.send("hey, I am Client. Nice to meet you!");
});
ws.addEventListener("error", (event)=> {
console.log('WebSocket error: ', event);
});
ws.addEventListener("message", ({data})=>{
console.log("Server sent us: "+data);
});
}
Server side code
main.ts
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import * as fs from 'fs';
async function bootstrap() {
const httpsOptions = {
key: fs.readFileSync('./localhost-key.pem'),
cert: fs.readFileSync('./localhost.pem'),
rejectUnauthorized: false,
};
const app = await NestFactory.create(AppModule, {
httpsOptions,
});
await app.listen(8090);
console.log('Server started at 8090');
}
bootstrap();
app.controller.ts
import { Controller, Get } from '#nestjs/common';
import { AppService } from './app.service';
#Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
#Get()
getSecureWssConn(): string {
return this.appService.getSecureWssConn();
}
}
app.service.ts
import { Injectable } from '#nestjs/common';
#Injectable()
export class AppService {
getSecureWssConn(): string {
// eslint-disable-next-line #typescript-eslint/no-var-requires
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8082 });
wss.on('connection', (ws) => {
console.log('New Client connected');
ws.on('message', (data) => {
console.log(`Client has sent us: ${data}`);
ws.send('Hello! I am Server. Nice to meet you.');
});
ws.on('close', () => {
console.log('Client Disconnected');
});
});
return 'Hello, I am your SERVER';
}
}
Server running in browser!

Nest.js equivalent program for below Node snippet

Can someone please help and tell me how I can write the following code snippet which is written as a node application to write as a nest application with just WebSockets and gateway class?
var webSocketsServerPort = 8080;
var webSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
});
server.listen(webSocketsServerPort, function() {
console.log(
new Date() + ' Server is listening on port ' + webSocketsServerPort
);
);
});
var wsServer = new webSocketServer({
httpServer: server
});
wsServer.on('request', function(request) {
var connection = request.accept(null, request.origin);
connection.on('message', function(data) {
var message = JSON.parse(data.utf8Data);
});
connection.on('close', function(connection) {});
EDIT:
In main.ts I wrote this :
app.useWebSocketAdapter(new WsAdapter(app));
This is how my gateway class looks like:
import { WebSocketGateway, WebSocketServer, OnGatewayInit, OnGatewayDisconnect, OnGatewayConnection, SubscribeMessage } from "#nestjs/websockets";
import { Server } from "websocket";
import { Logger } from "#nestjs/common";
#WebSocketGateway(8080)
export class ChatterGateway implements OnGatewayInit, OnGatewayDisconnect, OnGatewayConnection {
#WebSocketServer() private server: server;
private logger: Logger = new Logger('ChatterGateway');
afterInit(server: server) {
this.logger.log('ChatGetway init');
}
handleConnection(client: any, data) {
this.logger.log('Client connected');
}
handleDisconnect(client: any) {
this.logger.log('Client disconnected');
}
#SubscribeMessage('request')
handleRequest(client: any, data) {
this.logger.log(data);
}
#SubscribeMessage('message')
handleMessage(client: any, data) {
this.logger.log(data);
}
}

NodeJS Angular 8 chat application not receiving messages in client

I made a NodeJS server and an Angular 8 client to send and receive messages with socket.io. The server does receive the message but does not send/angular does not receive the message. Does this happen because I use localhost or did I do something wrong codewise?
NodeJS server:
let express = require('express');
let app = express();
let http = require('http');
let server = http.Server(app);
let socketIO = require('socket.io');
let io = socketIO(server);
const port = process.env.PORT || 3000;
io.on('connection', (socket) => {
console.log('user connected');
socket.on('new-message', (message) => {
console.log(message);
io.emit(message);
});
});
server.listen(port, () => {
console.log(`started on port: ${port}`);
});
Angular service:
import * as io from 'socket.io-client';
import { Observable } from 'rxjs/Observable';
import {Observer} from 'rxjs';
export class ChatService {
private url = 'http://localhost:3000';
private socket;
constructor() {
this.socket = io(this.url);
}
public sendMessage(message) {
this.socket.emit('new-message', message);
}
public getMessages = () => {
// return Observable.create((observer) => {
// console.log(observer);
// this.socket.on('new-message', (message) => {
// observer.next(message);
// });
// });
return new Observable((observer) => {
this.socket.on('new-message', (message) => {
observer.next(message);
observer.complete();
});
});
}
}
Angular component:
export class HomeComponent implements OnInit {
private message: string;
constructor(private chatService: ChatService) {
this.message = 'hello';
this.sendMessage();
}
ngOnInit(): void {
this.chatService.getMessages().subscribe((message: string) => {
console.log(message);
}, err => {
console.log(err);
});
}
sendMessage() {
this.chatService.sendMessage(this.message);
}
}
App.module.ts:
#NgModule({
declarations: [
AppComponent,
HomeComponent
], imports: [
], providers: [
ChatService
], entryComponents: []
})
export class AppModule {
}
In your server code you wrote io.emit(message); but emit function is called with two parameters - event name, and message to send.
Change it into io.emit('new-message', message); and it should work.
you need to change io.emit(message) to io.emit("message", { message: message }).
this code worked for me.

How to receive data from client using socket.io events inside express controller?

I am using Express framework with TypeScript:
I want to get client location at login using Socket IO, so on the client side, i made an emit event on login page. On the server side i tried to integrate a socket event into the login controller, which is placed before the response is sent back to the client, but the event from the server fires up just after i'm already signed in and clicked on sign out button which leads me to login page again (this is the moment when i receive the location message on server side from console.log(data)).
This is how the authentication controller file (auth.controller.ts) looks like:
import { io } from '../server/https';
....
..
public authenticate(req: Request, res: Response) {
if(req.body.email && req.body.password) {
....
..
io.on('connection', (socket: SocketIO.Socket) => {
console.log('New Socket Connected!');
socket.on('client-location', (data) => {
console.log(data);
});
socket.on('disconnect', (reason) => {
console.log(reason);
});
});
res.status(200).json({
resType: 'success',
token: 'Bearer ' + token,
userId: user.id,
message: 'Authenticated.',
loginNumber: result.session.length
});
};
....
..
}
The { io } import in the auth.controller.ts is the exported io constant from https.ts file.
Below is the https.ts file:
import socketIO from 'socket.io';
import HTTPS from 'https';
import app from '../app/index';
....
..
const options = {
cert: fs.readFileSync(path.resolve('../../../certificates/ca.crt')),
key: fs.readFileSync(path.resolve('../../../certificates/ca.key'))
}
export const server = HTTPS.createServer(options, app)
.listen(process.env.HTTP_SERVER_PORT, () => {
console.log(`Platform Server is running from
${process.env.HTTP_SERVER_HOST}, port: ${process.env.HTTP_SERVER_PORT}`);
});
export const io = socketIO.listen(server);
Something is not synchronized and i don't get it.
The client side is wrote in Angular 6 and the component from where the event is emited is below:
import { Component, OnInit } from '#angular/core';
import { LoginService } from '../../services/login.service';
import { Router } from '#angular/router';
import * as io from 'socket.io-client';
import { env } from '../../../../../environments/environment';
#Component({
selector: 'login-form',
templateUrl: './login-form.component.html',
styleUrls: ['./login-form.component.css']
})
export class LoginFormComponent implements OnInit {
public positionOptions = {
enableHighAccuracy: true,
maximumAge: 0
};
public LoginFormModel: any = {};
private URL = `${env.WS_SERVER_URL}:${env.HTTP_SERVER_PORT}`;
private socket;
constructor(private loginController: LoginService,
private router: Router) {
this.socket = io(this.URL);
}
ngOnInit() {}
public emitLocation() {
navigator.geolocation.getCurrentPosition(position => {
const { latitude: lat, longitude: lng } = position.coords;
console.log({ lat, lng });
this.socket.emit('client-location', { lat, lng });
},
err => {
console.log(err);
}, this.positionOptions);
}
loginEvent() {
this.loginController.login(this.LoginFormModel.email.value,
this.LoginFormModel.password.value)
.subscribe(
result => {
this.loginController.createSession('token', result.token);
this.emitLocation();
this.router.navigate(['user/profile']);
},
err => {
console.log(err);
});
}
}

socket.io client in ionic 3 is not working?

I am trying to make a socket io client I am able to connect but I am not able to emit or receive message.I have create a web app Where If any user connect it shows new user is connected, so If I open My app It shows new user is connected but when I send message It does not show on the either side
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import * as io from 'socket.io-client';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
socket:any;
socketURL:any;
constructor(public navCtrl: NavController) {
this.socketURL = "my url";
this.socket = io(this.socketURL);
this.socket.on('connect',()=> {
console.log('connected from server');
})
this.socket.emit('createMessage', 'hello worlddddddddd');
this.socket.on('newMessage', (message)=>{
alert('new massage'+JSON.stringify(message));
}
)
}
ionViewWillleave(){
this.socket.on('disconnect',()=> {
console.log('disconnected from server');
});
}
}
I have this in my case and it works.
constructor(privatesocketService: SocketService, privatesocket: Socket){
this.socket.on('message', (data) = > {
console.log('message : ' + data);
});
}
ionViewDidLeave(){
console.log('ionViewDidLeave ChatRoomPage');
this.socketService.leaveConversation(this.conversationId);
}
ionViewDidLoad(){
console.log('ionViewDidLoad ChatRoomPage');
this.socketService.joinConversation(this.conversationId);
this.getUsers();
}
sendMessage(){
this.conversationService.sendMessage(this.conversationId, this.message);
}
import {Injectable} from '#angular/core';
import {Socket} from 'ng-socket-io';
#
Injectable()
export class SocketService {
constructor(privatesocket: Socket) {
this.socket.connect();
}
joinConversation(conversationId) {
this.socket.emit('enter-room', conversationId);
}
leaveConversation(conversationId) {
this.socket.emit('leave-room', conversationId);
}
sendMessage(conversationId) {
this.socket.emit('new-message', conversationId);
}
}

Resources