How to make Socket.IO serveClient option work? - javascript

I'd like to use client distrubuted with the socket.io package in client-side scripts.
This is what I did:
const IOserver = io.listen(server, { serveClient: true, path: "/socket.io.client.js" });
But when I try to access socket.io client on that path http://localhost:1337/socket.io.client.js I get a 404 error.
How to properly set up socket.io to serve client side JavaSript file?

I think you are confusing what the path properties does. The path is the endpoint it should use to connect to your websocket server.
You need to manage the installation of the frontend js client manually. It does not get fed in from your server.

I just met the problem.
If you want the serverClient option to work, you need to do as follows:
http version
// app.js file
const server = require('http').createServer((req, res) => {
fs.readFile(__dirname + '/index.html',
(err, data) => {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
});
const io = require('socket.io')(server, { serveClient: true });
server.listen(1234, () => {
console.log('Server listening at http://localhost:1234.');
})
Or express version:
const express = require('express');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server, { serveClient: true });
server.listen(1234, () => {
console.log('Server listening at http://localhost:1234.');
})
And then, you can obtain the socket.io.js file by link http://localhost:1234/socket.io/socket.io.js, or socket.io.js.map file by link http://localhost:1234/socket.io/socket.io.js.map.

Related

How to separate all of socket.io to a different file

Right now, I have app.js where I have my usual code and my socket.io code. But what I want to do is, separate every single code of socket.io into 1 different file and require that socket.io code from the different file into my main app.js. Is there any way to do it writing 2/3 lines of code into my app.js to require socket.io from a different file?
Note: I do not want to write any of my socket.io code into my app.js so I do not know if it would be possible to require('....') it into my app.js from a different file. Ideally want to separate everything within io.on('connection'){}
const express = require('express');
const http = require('http'); // socket.io is created upon http server. A way to create server
const cors = require('cors');
const {Server} = require('socket.io');
const app = express();
app.use(cors());
const server = http.createServer(app); // this is to create http server with express for socket.io
const io = new Server(server, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"]
}
});
io.on("connection", (socket) => {
socket.on("newUser", (username) => {
addNewUser(username, socket.id);
console.log('connect print: '); printUsers();
})
socket.on("disconnect", () => {
removeUser(socket.id);
console.log('disconnect print: '); printUsers();
});
})
server.listen(3001, () => {
console.log('server listening on port 3001');
})
There would be a few way to do this but something like below should work.
In your new file, use module.exports to export an object containing any functions or objects you want to export:
//socketio.js
module.exports = {
getIo: (server) => {
const io = new Server(server, {
//...
});
io.on("connection", (socket) => {
//...
}
//your other functions
return io;
}
}
Then in your app.js, require it and use the object's properties:
//app.js
const socketio = require('./socketio.js');
//after creating your server etc
const io = socketio.getIo(server);

node.js server can't receive any calls unless an empty folder is created on the server

I'm probably doing something silly, and putting myself in a situation that I don't need to be in. But my ultimate question is why do I have to have an empty folder in my server in order for my GET requests to work?
Before I start with an example, everything is under a subfolder: http://www.example.org/subfolder1
Here is Server code:
const express = require('express');
const datastore = require('nedb');
const url = require("url");
var path = require('path');
const app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server,
{
path: '/subfolder1/socket.io',
cors:
{
origin: '*',
methods: ["GET", "POST"],
credentials: true
}
});
const port = 3000;
io.on('connection', socket => {
console.log("Socket connected: " + socket.id);
});
app.get("/subfolder1/getSettings", (req, res, next) => {
res.json({ configuration: conf });
});
app.use(express.json());
app.get("/subfolder1/", function (req, res) {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
app.use(express.static(path.join(__dirname, 'public')));
server.listen(port, '0.0.0.0', function(error){
if(error) {
console.log('Server failed to listen: ', error)
} else{
console.log('Server is listening on port: ' + port)
}
});
client code:
const response = await fetch("/subfolder1/getSettings");
const settings = await response.json();
Now, in this example I'm calling getSettings (http://www.example.org/subfolder1/getSettings):
app.get("/subfolder1/getSettings", (req, res, next) => {
res.json({ configuration: conf });
});
No matter what I do, I will forever get a 404 error message unless I create an empty folder called "getSettings" in my folder structure on my server. Once I create the empty folder, the call works! So for now, I've just making empty folders on my server for my get calls. Well now look what happens when the URL is something more complicated, such as the following:
http://www.example.org/subfolder1/team=6/queuedPlayers (Where team can be any integer)
Now I'm stuck and my workaround is broken. Any ideas?

node, express, body-parser - can't read js file from src

may be its dumb question but I can't find answer yet. :(
I made app using create-react-app, and server file:
server.js
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');
const PORT = process.env.PORT || 3000;
const app = express();
const p = path.parse(__dirname);
app.use(express.static('public'));
app.get('/', (req, res) => {
const filePath = path.join(p.dir, 'src', 'index.js');
fs.readFile(filePath, {encoding: 'utf-8'},(err, data) => {
if (err) {
throw err;
}
res.send(data);
});
});
app.listen(PORT, () => {
console.log(`Started at port ${PORT}`);
});
tryied to read index.js file from app src directory but all i got in browser is plain text. I can only run static files from public directory. What i did wrong and how should i run js files of react app using express in node?
You need to send the index.html file that is built by react. A browser can only open a web page from a html file.
You need to first build your react app using npm run build
Then serve it with express with something like
app.get('*', (req,res) => {
res.sendFile('/build/index.html'); // wherever react creates the index.html
});
To give you a basic idea on express,
const express = require('express')
const app = express()
app.get('', (req, res) => {
res.render('index') // index is an html file or a template (ejs, hbs, etc..)
})
// You can't directly send js files
app.get('/info', (req, res) => {
res.render('info', {
title: 'info page',
message: 'welcome to the info page'
})
})
// You can't directly send js files
app.listen(3000, () => {
console.log('Server is up on port 3000.')
})
If you want to send json
const leaderboardHistory = require("relativepath/leaderboardHistory.json")
app.get("/leaderboardhistory", function(req, res){
res.render("leaderboardhistory", {leaderboardHistory : leaderboardHistory});
});

How to send ws message from route request

I've been trying to create an app that uses telegram-bot, express server and react app. Therefore, I need to create a POST request from telegram-bot to express, while express sends POST data to a websocket connection:
const express = require("express");
const app = express();
const expressWs = require("express-ws")(app);
// handles bot request
app.post("/request", (req, res) => {
playlist.push(req.body.url);
res.status(200).send({ message: "video is added to playlist" });
});
// after handling requst data must go here and send ws message to client side
app.ws("/echo", (ws, req) => {
ws.on("message", msg => {
ws.send(`msg is = ${msg}`);
});
});
Am I making it right, and if so, how to call ws.send from after handling request at app.post route?
From the understanding I have from your question, here is an updated version of your code that does exactly what you want.
I replaced the express-ws package with ws since that would be sufficient for your use case.
The express server runs on port 8080 while the websocket server runs on port 8081 since are different protocols and would not run on the same port (You can make it work but I do not recommend it See this question
const express = require("express");
const Websocket = require('ws');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const wss = new Websocket.Server({ port: 8081 });
wss.on('connection', (ws) => {
console.log('One client connected');
ws.on("message", msg => {
ws.send(`msg is = ${msg}`);
});
})
// handles bot request
app.post("/request", (req, res) => {
// Broadcast URL to connected ws clients
wss.clients.forEach((client) => {
// Check that connect are open and still alive to avoid socket error
if (client.readyState === Websocket.OPEN) {
client.send(url);
}
});
res.status(200).send({ message: "video is added to playlist" });
});
app.listen(8080, () => {
console.log('Express listening on 8080');
console.log('Websocket on 8081');
});
Tested via curl with curl -d 'url=https://example.com/examplesong' localhost:8080/request I had a client connected to ws://localhost:8081 and everything looks good.

NodeJS Express - Return the JSON file of the URL path that it triggered

I trying to write a NodeJS project that read JSON files from the project directory and response back the JSON file data whenever, user trigger a specific URL.
For the Project below, I am able to get the JSON data response when I trigger http://localhost:8081/api/user in web browser.
In order to make this work I have to explicitly hardcode a function that response to a specific URL. For example, if I wanted to add 1 more JSON files in the api folder and enable user to access it, I have to explicitly hardcode another function just to response to different request.
app.get('/api/newJSONFile', (req, res) => {
fs.readFile( __dirname +'/api/newJSONFile' +".json", 'utf8', function (err, data) {
res.send(data);
res.end( data );
});
});
So, after adding the code above the user will able to access the JSON file through http://localhost:8081/api/newJsonFile. Without the explicitly hardcode
function above user will not able to get response when launch the http://localhost:8081/api/newJsonFile
My Question:
Is this the only way to perform the response upon URL request? It seem inefficient, as if I have 100 JSON File then I have to explicitly hardcode another 100 functions.
What is the proper way to code the implementation?
Thank you.
My Project Structure:
server.js
const express = require('express');
const app = express();
const fs = require("fs");
app.get('/api/user', (req, res) => {
fs.readFile( __dirname +'/api/user' +".json", 'utf8', function (err, data) {
res.send(data);
res.end( data );
});
});
var server = app.listen(8081, () => {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
You can use the express static middleware to serve static json files from a specified folder.
const express = require('express');
const app = express();
// Setup express static middleware to look for files in the api directory for all requests starting with /api
app.use('/api', express.static('api') , function(req, res){
// Optional 404 handler
res.status(404);
res.json({error:{code:404}})
});
var server = app.listen(8081, () => {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
You can then access your user.json in the folder /api/user.json at localhost:8081/api/user.json
EDIT:
If you want to be able to add multiple folders, you can create a designated public (you can call it anything, actually) directory and put all your top level folders there.
Consider the following JSON files stored in a nested fashion:
/public/api/user.json [ One level nest in api folder]
/public/data/config.json [ One level nest in data folder]
/public/data/server/config.json [Two level nest in data -> server folder]
you can then do
const express = require('express');
const app = express();
// EDIT: added options to ensure json can be accessed without extension
app.use(express.static('public',{index:false, extensions:['json']}));
app.use(function (req, res) {
// Optional 404 handler
res.status(404);
res.json({
error: {
code: 404
}
});
})
var server = app.listen(8081, () => {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
and then access your files as :
localhost:8081/api/user.json OR localhost:8081/api/user
localhost:8081/data/config.json OR localhost:8081/data/config
localhost:8081/data/server/config.json OR localhost:8081/data/server/config
Reference for options accepted by the express static middleware
Additional Improvement
NOTE: This method may accidentally expose sensitive server side configuration files [like your package.json] and potentially your entire codebase. Please use this method carefully and only if you know what you are doing.
If you do not want to create a designated directory (in this case 'public' folder) and put all your top level folders there in order to access it, you can use the code below to dynamically serve your files:
const express = require('express');
const app = express();
var publicdir = __dirname + '/';
app.use(express.static(publicdir,{extensions:['json']})); //or ,{index:false, extensions:['json']}
app.use(function (req, res) {
res.status(404);
res.json({
error: {
code: 404
}
});
})
var server = app.listen(8081, () => {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
You could expect file name in the url and then use just one route handler to deliver JSON files.
app.get('/api/:jsonFile', (req, res) => {
fs.readFile( __dirname +'/api/' + req.params.jsonFile +".json", 'utf8', function (err, data) {
res.send(data);
res.end( data );
});
});
Do add proper error handling like if file does not exists, then send back 404 using something like below:
if (!fs.existsSync(path)) {
res.status(404).send("");
}
Edit:
To return pretty JSON object try using the following:
res.header("Content-Type",'application/json');
res.send(JSON.stringify(YOUR_JSON_OBJECT, null, 4));
Express supports parameters in your route.
So having an arbitrary string from the url is as easy as modifying your route to :
app.get('/api/:file', (req, res) => {
fs.readFile( __dirname +'/api/' + req.params.file + ".json", 'utf8', function (err, data) {
res.send(data);
res.end( data );
});
});

Categories