(See update below for a working example)
TL;DR - example:
Original answer
There are few problems with your code:
- you're not checking for errors
- you're using blocking functions
- you're implicitly relying on file permissions but you're not checking it
- you're using string concatenation instead of
path.join
to join paths
- you're constantly polling for new data instead of waiting for it to change
- you're not catching exceptions of functions that can raise exception
- you're not waiting for async operations to finish and you don't handle errors
The main problem that you're experiencing right now is most likely with the file permissions. The good news is that you don't need any file access for what you're doing and using files for that is not optimal anyway. All you need is to store the color in a variable if you don't need it it persist between server restarts - and even if you do then I would use a simple database for that.
For example:
// some initial value:
var color = '#ffffff';
app.post("/message", function (request, response) {
var color = request.body.Body;
response.end();
});
// get the saved color (reading from disk)
app.get("/color", function (request, response) {
response.send(color);
});
app.get("/", function (request, response) {
response.sendFile(__dirname + '/views/index.html');
});
var listener = app.listen(process.env.PORT, function () {
console.log('listening on port ' + listener.address().port);
});
This is the first change that I would use - don't rely on the file system, permissions, race conditions etc.
Another problem that you had with your code was using blocking functions inside of request handlers. You should never use any blocking function (those with "Sync" in their name) except the first tick of the event loop.
Another improvement that I would make would be using WebSocket or Socket.io instead of polling for data on regular intervals. This would be quite easy to code. See this answer for examples:
A plus of doing that would be that all of your students would get the color changed instantly and at the same time instead of in random moments spanning 2 seconds.
Update
I wrote an example of what I was describing above.
The POST endpoint is slightly different - it uses /color
route and color=#abcdef
instead of /message
and Body=...
but you can easily change it if you want - see below.
Server code - server.js:
// requires removed for brevity
const app = express();
const server = http.Server(app);
const io = socket(server);
let color = '#ffffff';
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/', express.static(path.join(__dirname, 'html')));
io.on('connection', (s) => {
console.log('Socket.io client connected');
s.emit('color', color);
});
app.post('/color', (req, res) => {
color = req.body.color;
console.log('Changing color to', color);
io.emit('color', color);
res.send({ color });
});
server.listen(3338, () => console.log('Listening on 3338'));
HTML page - index.html:
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<meta name=viewport content="width=device-width, initial-scale=1">
<title>Node Live Color</title>
<link href="/style.css" rel=stylesheet>
</head>
<body>
<h1>Node Live Color</h1>
<script src="/socket.io/socket.io.js"></script>
<script src="/script.js"></script>
</body>
</html>
Style sheet - style.css:
body {
transition: background-color 2s ease;
background-color: #fff;
}
Client-side JavaScript - script.js:
var s = io();
s.on('color', function (color) {
document.body.style.backgroundColor = color;
});
What is particularly interesting is how simple is the client side code.
For your original endpoint use this in server.js:
app.post('/message', (req, res) => {
color = req.body.Body;
console.log('Changing color to', color);
io.emit('color', color);
res.end();
});
Full example is available on GitHub:
I tested it locally and on Heroku. You can click this button to deploy it on Heroku and test yourself:
Enjoy.