Skip to content

Commit df770fa

Browse files
Add nginx cluster example
1 parent b754cff commit df770fa

File tree

10 files changed

+697
-0
lines changed

10 files changed

+697
-0
lines changed

examples/cluster-nginx/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
# Socket.IO Chat with nginx & redis
3+
4+
A simple chat demo for socket.io
5+
6+
## How to use
7+
8+
Install [Docker Compose](https://docs.docker.com/compose/install/), then:
9+
10+
```
11+
$ docker-compose up -d
12+
```
13+
14+
And then point your browser to `http://localhost:3000`.
15+
16+
This will start four Socket.IO nodes, behind a nginx proxy which will loadbalance the requests (using the IP of the client, see [ip_hash](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash)).
17+
18+
Each node connects to the redis backend, which will enable to broadcast to every client, no matter which node it is currently connected to.
19+
20+
```
21+
# you can kill a given node, the client should reconnect to another node
22+
$ docker-compose stop server-george
23+
```
24+
25+
## Features
26+
27+
- Multiple users can join a chat room by each entering a unique username
28+
on website load.
29+
- Users can type chat messages to the chat room.
30+
- A notification is sent to all users when a user joins or leaves
31+
the chatroom.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
2+
nginx:
3+
build: ./nginx
4+
links:
5+
- server-john
6+
- server-paul
7+
- server-george
8+
- server-ringo
9+
ports:
10+
- "3000:80"
11+
12+
server-john:
13+
build: ./server
14+
links:
15+
- redis
16+
expose:
17+
- "3000"
18+
environment:
19+
- NAME=John
20+
21+
server-paul:
22+
build: ./server
23+
links:
24+
- redis
25+
expose:
26+
- "3000"
27+
environment:
28+
- NAME=Paul
29+
30+
server-george:
31+
build: ./server
32+
links:
33+
- redis
34+
expose:
35+
- "3000"
36+
environment:
37+
- NAME=George
38+
39+
server-ringo:
40+
build: ./server
41+
links:
42+
- redis
43+
expose:
44+
- "3000"
45+
environment:
46+
- NAME=Ringo
47+
48+
redis:
49+
image: redis:alpine
50+
expose:
51+
- "6379"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
FROM nginx:alpine
3+
COPY nginx.conf /etc/nginx/nginx.conf
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Reference: https://www.nginx.com/resources/wiki/start/topics/examples/full/
2+
3+
worker_processes 4;
4+
5+
events {
6+
worker_connections 1024;
7+
}
8+
9+
http {
10+
server {
11+
listen 80;
12+
13+
location / {
14+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
15+
proxy_set_header Host $host;
16+
17+
proxy_pass http://nodes;
18+
19+
# enable WebSockets
20+
proxy_http_version 1.1;
21+
proxy_set_header Upgrade $http_upgrade;
22+
proxy_set_header Connection "upgrade";
23+
}
24+
}
25+
26+
upstream nodes {
27+
# enable sticky session
28+
ip_hash;
29+
30+
server server-john:3000;
31+
server server-paul:3000;
32+
server server-george:3000;
33+
server server-ringo:3000;
34+
}
35+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM mhart/alpine-node:6
2+
3+
# Create app directory
4+
RUN mkdir -p /usr/src/app
5+
WORKDIR /usr/src/app
6+
7+
# Install app dependencies
8+
COPY package.json /usr/src/app/
9+
RUN npm install
10+
11+
# Bundle app source
12+
COPY . /usr/src/app
13+
14+
EXPOSE 3000
15+
CMD [ "npm", "start" ]
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Setup basic express server
2+
var express = require('express');
3+
var app = express();
4+
var server = require('http').createServer(app);
5+
var io = require('socket.io')(server);
6+
var redis = require('socket.io-redis');
7+
var port = process.env.PORT || 3000;
8+
var serverName = process.env.NAME || 'Unknown';
9+
10+
io.adapter(redis({ host: 'redis', port: 6379 }));
11+
12+
server.listen(port, function () {
13+
console.log('Server listening at port %d', port);
14+
console.log('Hello, I\'m %s, how can I help?', serverName);
15+
});
16+
17+
// Routing
18+
app.use(express.static(__dirname + '/public'));
19+
20+
// Chatroom
21+
22+
var numUsers = 0;
23+
24+
io.on('connection', function (socket) {
25+
socket.emit('my-name-is', serverName);
26+
27+
var addedUser = false;
28+
29+
// when the client emits 'new message', this listens and executes
30+
socket.on('new message', function (data) {
31+
// we tell the client to execute 'new message'
32+
socket.broadcast.emit('new message', {
33+
username: socket.username,
34+
message: data
35+
});
36+
});
37+
38+
// when the client emits 'add user', this listens and executes
39+
socket.on('add user', function (username) {
40+
if (addedUser) return;
41+
42+
// we store the username in the socket session for this client
43+
socket.username = username;
44+
++numUsers;
45+
addedUser = true;
46+
socket.emit('login', {
47+
numUsers: numUsers
48+
});
49+
// echo globally (all clients) that a person has connected
50+
socket.broadcast.emit('user joined', {
51+
username: socket.username,
52+
numUsers: numUsers
53+
});
54+
});
55+
56+
// when the client emits 'typing', we broadcast it to others
57+
socket.on('typing', function () {
58+
socket.broadcast.emit('typing', {
59+
username: socket.username
60+
});
61+
});
62+
63+
// when the client emits 'stop typing', we broadcast it to others
64+
socket.on('stop typing', function () {
65+
socket.broadcast.emit('stop typing', {
66+
username: socket.username
67+
});
68+
});
69+
70+
// when the user disconnects.. perform this
71+
socket.on('disconnect', function () {
72+
if (addedUser) {
73+
--numUsers;
74+
75+
// echo globally that this client has left
76+
socket.broadcast.emit('user left', {
77+
username: socket.username,
78+
numUsers: numUsers
79+
});
80+
}
81+
});
82+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "socket.io-chat",
3+
"version": "0.0.0",
4+
"description": "A simple chat client using socket.io",
5+
"main": "index.js",
6+
"author": "Grant Timmerman",
7+
"private": true,
8+
"license": "BSD",
9+
"dependencies": {
10+
"express": "4.13.4",
11+
"socket.io": "^1.7.2",
12+
"socket.io-redis": "^3.0.0"
13+
},
14+
"scripts": {
15+
"start": "node index.js"
16+
}
17+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Socket.IO Chat Example</title>
6+
<link rel="stylesheet" href="style.css">
7+
</head>
8+
<body>
9+
<ul class="pages">
10+
<li class="chat page">
11+
<div class="chatArea">
12+
<ul class="messages"></ul>
13+
</div>
14+
<input class="inputMessage" placeholder="Type here..."/>
15+
</li>
16+
<li class="login page">
17+
<div class="form">
18+
<h3 class="title">What's your nickname?</h3>
19+
<input class="usernameInput" type="text" maxlength="14" />
20+
</div>
21+
</li>
22+
</ul>
23+
24+
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
25+
<script src="/socket.io/socket.io.js"></script>
26+
<script src="/main.js"></script>
27+
</body>
28+
</html>

0 commit comments

Comments
 (0)