Angular Node | SocketIO | Event not emitted from node - javascript

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.

Related

Socket.io on Heroku does not run as expected

I have a MERN application. I want to run this on Heroku. That also works so far. But I can't get socket.io to run on Heroku. My server listens on port 5555. Below I have listed all possible scenarios that I have already tried without success. What else can I do ?
I specify "ws://localhost:5555" or "http://localhost:5555" whatever it is, it works with a local address.
Thank you very much!
index.js Server
import express from "express";
import http from "http";
import { Server } from "socket.io";
const app = express();
const server = http.createServer(app);
const socketio = new Server(server, { cors: { origin: "*" } });
socketio.on("connect", (socket) => {
socket.on("addUser", (userId) => {
addUser(userId, socket.id);
console.log(users);
});
...
});
app.listen(process.env.PORT || 5050, () => {
verbindugZuMongoDb();
});
server.listen(5555);
App.js
import { io } from "socket.io-client";
useEffect(() => {
setSocket(io("wss://example.herokuapp.com:5555/")); // Also not working
setSocket(io("https://example.herokuapp.com:5555/")); // Also not working
setSocket(io()); // Also not working
setSocket(io(":5555")); // Also not working
setSocket(io("https://example.herokuapp.com/")); // Also not working
}, []);

Vue.js + Nuxt.js: Can't connect with socket server using socket.io-client

I am using for client and server sides: socket.io-client v3.0.5
index.vue
import socket from '~/plugins/socket.js'
<script>
mounted() {
socket.open()
}
</script>
plugins/socket.js
import io from 'socket.io-client'
const options = {
path: '/socket.io',
transports: ['websocket'],
forceNew: true,
reconnectionAttempts: 3,
timeout: 2000,
reconnection: false,
}
const socket = io(process.env.PROXY_SOCKET_URL, options)
export default socket
nuxt.config.js
plugins: [
'~/plugins/socket.js',
],
And on mount i got this: 2 commas after '40' code in data of ws
My client side and server side not connecting because of 2 commas in data. I tested my socket server via SocketIo Client tool and it works.
My frontend and backend in docker.
How can i remove those commas?
You can use "nuxt-socket-io"(v1.1.18) module instead of socket.io-client. It helped me connect front and server.
Here my realization:
nuxt.config.js
modules: [
'nuxt-socket-io',
],
io: {
// module options
sockets: [
{
name: 'main',
default: true,
url: process.env.PROXY_SOCKET_URL,
},
],
},
index.vue
<script>
mounted() {
window.socket = this.$nuxtSocket({
path: '/socket.io',
transport: ['websocket'],
})
window.socket.open()
}
</script>
I've been playing with this the past few days, and have a module-free solution.
In order to run the socket.io server on the same server that nuxt is providing we need to get access to Nuxt's server. Luckily, Nuxt's listen hook provides the server once it has been started. We can use this server to start our socket.io server by adding the following to nuxt.config.ts:
import startSocketServer from "./server/sockets"
defineNuxtConfig({
...
hooks: { listen: (server) => startSocketServer(server) },
...
})
and inside of ~/server/sockets/index.ts we export a function that accepts this server and spins up the socket.io server:
import { Server as NuxtServer } from 'node:http'
import { Socket, Server } from "socket.io";
export default (nuxtServer: NuxtServer) => {
const io = new Server(nuxtServer)
io.on("connection", (socket: Socket) => {
socket.emit('message', "Hello World")
});
};
That's it for the server!
If we now have an app.vue that looks like this:
<script setup lang="ts">
import { io } from "socket.io-client";
const socket = io();
onMounted(() => socket.connect());
onUnmounted(() => socket.close());
const message = ref("");
socket.on("message", (data: string) => (message.value = data));
</script>
<template>
<div>{{ message }}</div>
</template>
We should see "Hello world" from the server when we load the page.

Express CORS is not working with socket.io

I've used cors for my express server, but I can't figure out why it's not working. Can anyone please help me with this issue?
Access to XMLHttpRequest at
'https://tic-tac-toe-server.now.sh/socket.io/?EIO=3&transport=polling&t=N6Z2b4X'
from origin 'http://localhost:8080' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested
resource.
Client:
import io from 'socket.io-client';
const socket = io('https://tic-tac-toe-server.now.sh')
Here is my index.js
const express = require('express');
const socketio = require('socket.io');
const http = require('http');
const cors = require('cors');
const router = require('./router');
const { addUser, removeUser, getUsers } = require('./users');
const { getMatch, addPlayer, destroyMatch } = require('./players');
const PORT = process.env.PORT || 5000;
const app = express();
const server = http.createServer(app);
const io = socketio(server);
app.use(router);
app.use(cors());
io.on('connection', function (socket) {
const id = socket.id;
let user_room = '';
/**
* User Joins to the global room
*/
socket.on('join', function ({ name, room, playing = false }) {
addUser({ id, name, room, playing }); // add user to users array
user_room = room;
socket.join(user_room);
socket.join(id);
socket.emit('user_joined', getUsers());
socket.broadcast.emit('user_joined', getUsers()); // emit event with modified users array
});
/**
* Match Started
*/
socket.on('player_joined', user => {
const match = getMatch();
addPlayer(user.match, user);
if(match.hasOwnProperty(user.match) && match[user.match].length === 2){
socket.emit('player_joined', match[user.match]);
socket.broadcast.to(user.match).emit('player_joined', match[user.match]);
}
});
socket.on('move', (data) => {
socket.emit('move', data);
socket.broadcast.to(data.match).emit('move', data);
});
socket.on('emote', (data) => {
socket.emit('emote_from', data);
socket.broadcast.to(data.match).emit('emote_to', data);
});
/**
* On user challenge
*/
socket.on('challenge', (socketId) => {
io.to(socketId).emit('accept', id);
});
socket.on('rejected', (socketId) => {
io.to(socketId).emit('rejected', id);
});
socket.on('accepted', data => {
io.to(data.opponent.id).emit('accepted', data);
socket.emit('accepted', data);
});
socket.on('player_left_match', match => {
socket.broadcast.to(match).emit('player_left_match');
});
socket.on('destroy_match', match => {
destroyMatch(match);
});
/**
* User Disconnect function
*/
socket.on('disconnect', () => {
socket.leave(user_room);
socket.leave(id);
removeUser(id); // remove user form users array
socket.emit('user_left', getUsers());
socket.broadcast.emit('user_left', getUsers()); // emit event with modified users
})
});
server.listen(PORT, () => console.log(`Server running on port ${PORT}`));
You can tell socket.io to only use the webSocket transport which is not subject to CORS by changing this:
const socket = io('https://tic-tac-toe-server.now.sh')
to this:
const socket = io('https://tic-tac-toe-server.now.sh', {transports: ['websocket']});
Some background. In its default configuration, socket.io starts every connection with multiple plain http requests. These plain http requests require server-side CORS support if the connection is cross-origin. But, socket.io can be configured to go straight to the webSocket transport (which is what is eventually ends up using anyway) and webSocket connections are not subject to CORS limitations.
The socket.io design to start with http polling was largely there because in the early days of webSocket support, not every browser supported it and not every server infrastructure supported it. But now-a-days, it is pretty widely supported.
So, telling socket.io to start with the webSocket transport from the beginning avoids many potential CORS issues.
We are now chasing a different issue and the error showing in the console at https://tic-tac-toe-vue.now.sh/ is coming from this code in webSocket.js.
try {
this.ws =
this.usingBrowserWebSocket && !this.isReactNative
? protocols
? new WebSocketImpl(uri, protocols)
: new WebSocketImpl(uri)
: new WebSocketImpl(uri, protocols, opts);
} catch (err) {
return this.emit('error', err);
}
It looks like something React related since there's a reference to isReactNative, but since your code is packaged and minimized, it's not very easy to do any debugging from here.

Socket IO namespace not working with Express

I have tried setting up a namespace on the backend,
const server = require("http").createServer(app);
const connectedUsers = {};
const io = require("socket.io")(server, {
path: "/socket",
serveClient: false,
// below are engine.IO options
pingInterval: 10000,
pingTimeout: 5000,
cookie: false
});
const singularConnection = io.of("/singular-socket");
singularConnection.on("connection", socket => {
console.log("unique user connected with socket ID " + socket);
}
And on my client, I try connecting with,
const socket = io(GATEWAY, {
path: "/socket/singular-socket",
transports: ["websocket"],
jsonp: false
});
socket.connect();
socket.on("connect", () => {
console.log("connected to socket server");
});
I've tried different variation of the URL, getting rid of /socket and moving other stuff around, but I can't seem to get it working. What am I doing wrong here?
I don't have any experience in using socket.io, but from the docs...
To connect to a namespace, the client code would look like.
const socket = io('http://localhost/admin', {
path: '/mypath'
});
Here, the socket connects to the admin namespace, with the custom path
mypath.
The request URLs will look like:
localhost/mypath/?EIO=3&transport=polling&sid= (the namespace is
sent as part of the payload).
Following the above lines, your code should look like..
const socket = io("http://localhost/singular-socket", {
path: "/socket",
transports: ["websocket"],
jsonp: false
})
Where /singular-socket is the namespace and /socket is the path.
Try this repl

get request throwing 404 error in Angular 5 app

I am a newbie to Angular.I am creating a demo video player app, following youtube series, but I am struck at a point where I can't get data for my get request.I am using Angular 5.2.10.Below are my files and code:
server.js:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const api = require('./server/routes/api');
const port = 3000;
const app = express();
app.use(express.static(path.join(__dirname,'dist')));
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
app.use('/api',api);
app.get('*',(req,res)=>{
res.sendFile(path.join(__dirname,'dist/index.html'));
});
app.listen(port,function(){
console.log("server running on localhost"+port);
});
api.js:
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const Video = require('../models/video');
const
db="mongodb://usersubhash:subhashpwd#ds217350.mlab.com:17350/videoplayer";
mongoose.Promise = global.Promise;
mongoose.connect(db,function(err){
if(err){
console.log("Error!"+err);
}
});
router.get('/videos',function(req,res){
//res.send('api works');
Video.find({}).exec(function(err,videos){
if(err){
console.log("error retrieving videos");
}else{
res.json(videos);
}
});
});
module.exports = router;
video.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const videoSchema = new Schema({
title:String,
url:String,
description:String
});
module.exports = mongoose.model('video',videoSchema,'videos');
video.ts:
export class Video {
_id:string;
title:string;
url:string;
description:string
}
environment.ts
export const environment = {
production: false,
apiUrl: 'http://localhost:3000'
};
video.service.ts:(where I have getVideos() method)
import { Injectable } from '#angular/core';
import {Http,Response} from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class VideoService {
constructor(private _http:Http) { }
private _getUrl = `${environment.apiUrl}/api/videos`;
getVideos(){
return this._http.get(this._getUrl).map((response:Response)=> response.json());
}
}
videoCenter.component.ts:(where I am subscribing to getVideos() method):
import { Component, OnInit } from '#angular/core';
import {Video} from '../video';
import { VideoService } from '../video.service';
#Component({
selector: 'app-video-center',
templateUrl: './video-center.component.html',
styleUrls: ['./video-center.component.css'],
providers:[VideoService]//,Http,HttpClientModule
})
export class VideoCenterComponent implements OnInit {
myAllVideos:Array;//here I want to put my get Request Data
constructor(private _videoService:VideoService) { }
selectedVideo:Video;
onSelectVideo (video:any){
this.selectedVideo=video;
}
ngOnInit() {
this._videoService.getVideos().subscribe(result => this.myAllVideos = result);
}
}
When I run node server.js in VSCode terminal , then in POSTMAN app I can get all records by requesting GET in "localhost:3000/api/videos".But in my app, I am unable to load data which is running in 4200 port.
When I click on button which loads video-center.component.ts , getVideos() is triggered in ngOnInit() but it throws this error:
Your screenshot showing the error has this url:
http://localhost:4200/api/videos
But your server.js says:
const port = 3000;
So your server is running on port 3000, not 4200. Port 4200 is normally where Angular runs.
So you need to modify your getUrl:
private _getUrl = "http://localhost:3000/api/videos";
Rather than hard code this I suggest you read-up on how to setup an environment file, and put the host part "http://localhost:3000" in the environment file and read it from there. Then your code could be:
private _getUrl = `${environment.apiUrl}/api/videos`;
NOTE
Just to be clear - although Angular runs on the client, it is an app that has to be started from somewhere. For example, in a production situation you might have this:
https://app.mydomain.com <- users visit this, and the browser starts running your angular app
https://api.mydomain.com <- your angular app will get its data from here
In production it's quite likely both of these urls will be accessed on port 80. But since the subdomains are different (api versus app) that is perfectly fine.
However, when running locally in development mode, you cannot run two different things (ie. an Angular application and a Node application) on the same address (localhost) with the same port.
Since you are running them both on localhost, they must have different ports. So when you wrote:
return this._http.get(this._getUrl)...
it is defaulting to where Angular itself is running, localhost:4200, not your api. You need to tell angular your api is on port 3000.

Categories