Skip to content

Commit ae8616b

Browse files
committed
add websocket romm
1 parent 7589171 commit ae8616b

File tree

21 files changed

+551
-79
lines changed

21 files changed

+551
-79
lines changed

js_notes/hello-koa/app.js

Lines changed: 174 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
*/
66
'use strict';
77

8+
const url = require('url');
9+
const ws = require('ws');
10+
const Cookies = require('cookies');
811
const Koa = require('koa');
9-
1012
const bodyParser = require('koa-bodyparser');
11-
1213
const controller = require('./controller');
13-
1414
const templating = require('./templating');
15+
const WebSocketServer = ws.Server;
1516

1617
// 创建一个Koa对象表示web app本身:
1718
const app = new Koa();
@@ -53,49 +54,45 @@ const isProduction = process.env.NODE_ENV === 'production';
5354
// console.log('created: ' + JSON.stringify(dog));
5455
// })();
5556

56-
const WebSocket = require('ws');
57-
const WebSocketServer = WebSocket.Server;
58-
const wss = new WebSocketServer({
59-
port: 3000
60-
});
61-
62-
wss.on('connection', function (ws) {
63-
console.log(`[SERVER] connection()`);
64-
ws.on('message', function (message) {
65-
console.log(`[SERVER] Receieved: ${message}`);
66-
setTimeout(() => {
67-
ws.send(`What's your name?`, (err) => {
68-
if (err) {
69-
console.log(`[SERVER] error: ${err}`);
70-
}
71-
});
72-
}, 1000);
73-
});
74-
});
75-
76-
console.log('ws server started at port 3000...');
57+
// const wss = new WebSocketServer({
58+
// port: 3000
59+
// });
60+
//
61+
// wss.on('connection', function (ws) {
62+
// console.log(`[SERVER] connection()`);
63+
// ws.on('message', function (message) {
64+
// console.log(`[SERVER] Receieved: ${message}`);
65+
// setTimeout(() => {
66+
// ws.send(`What's your name?`, (err) => {
67+
// if (err) {
68+
// console.log(`[SERVER] error: ${err}`);
69+
// }
70+
// });
71+
// }, 1000);
72+
// });
73+
// });
7774

7875
// client test:
79-
let count = 0;
80-
let ws = new WebSocket('ws://localhost:3000/ws/chat');
81-
82-
ws.on('open', function () {
83-
console.log(`[CLIENT] open()`);
84-
ws.send('Hello!');
85-
});
86-
87-
ws.on('message', function (message) {
88-
console.log(`[CLIENT] Received: ${message}`);
89-
count++;
90-
if (count > 3) {
91-
ws.send('Goodbye!');
92-
ws.close();
93-
} else {
94-
setTimeout(() => {
95-
ws.send(`Hello, I'm Mr No.${count}!`);
96-
}, 1000);
97-
}
98-
});
76+
// let count = 0;
77+
// let ws = new WebSocket('ws://localhost:3000/ws/chat');
78+
//
79+
// ws.on('open', function () {
80+
// console.log(`[CLIENT] open()`);
81+
// ws.send('Hello!');
82+
// });
83+
//
84+
// ws.on('message', function (message) {
85+
// console.log(`[CLIENT] Received: ${message}`);
86+
// count++;
87+
// if (count > 3) {
88+
// ws.send('Goodbye!');
89+
// ws.close();
90+
// } else {
91+
// setTimeout(() => {
92+
// ws.send(`Hello, I'm Mr No.${count}!`);
93+
// }, 1000);
94+
// }
95+
// });
9996

10097
// log request URL
10198
app.use(async (ctx, next) => {
@@ -108,12 +105,18 @@ app.use(async (ctx, next) => {
108105
ctx.response.set('X-Response-Time', `${execTime}ms`);
109106
});
110107

108+
// parse user from cookie:
111109
app.use(async (ctx, next) => {
112-
var name = ctx.request.query.name || 'world';
113-
ctx.response.type = 'text/html';
114-
ctx.response.body = `<h1>Hello, ${name}!</h1>`;
110+
ctx.state.user = parseUser(ctx.cookies.get('name' || ''));
111+
await next();
115112
});
116113

114+
// app.use(async (ctx, next) => {
115+
// var name = ctx.request.query.name || 'world';
116+
// ctx.response.type = 'text/html';
117+
// ctx.response.body = `<h1>Hello, ${name}!</h1>`;
118+
// });
119+
117120
// static file support:
118121
if (!isProduction) {
119122
let staticFiles = require('./static-files');
@@ -124,12 +127,130 @@ if (!isProduction) {
124127
app.use(bodyParser());
125128

126129
// add nunjucks as view:
127-
// app.use(templating('views', {
128-
// noCache: !isProduction,
129-
// watch: !isProduction
130-
// }));
130+
app.use(templating('views', {
131+
noCache: !isProduction,
132+
watch: !isProduction
133+
}));
131134

132135
// add controller:
133-
// app.use(controller());
136+
app.use(controller());
137+
138+
let server = app.listen(3000);
139+
140+
function parseUser(obj) {
141+
if (!obj) {
142+
return false;
143+
}
144+
145+
console.log('try parse: ' + obj);
146+
let s = '';
147+
if (typeof obj === 'string') {
148+
s = obj;
149+
} else if (obj.headers) {
150+
let cookies = new Cookies(obj, null);
151+
s = cookies.get('name');
152+
}
153+
if (s) {
154+
try {
155+
let user = JSON.parse(Buffer.from(s, 'base64').toString());
156+
console.log(`User: ${user.name}, ID: ${user.id}`);
157+
return user;
158+
} catch (e) {
159+
// ignore
160+
console.log(e);
161+
}
162+
}
163+
}
164+
165+
function createWebSocketServer(server, onConnection, onMessage, onClose, onError) {
166+
let wss = new WebSocketServer({
167+
server: server
168+
});
169+
170+
wss.broadcast = function broadcast(data) {
171+
wss.clients.forEach(function each(client) {
172+
client.send(data);
173+
});
174+
};
175+
onConnection = onConnection || function () {
176+
console.log('[WebSocket] connected.');
177+
};
178+
onMessage = onMessage || function (msg) {
179+
console.log('[WebSocket] message received: ' + msg);
180+
};
181+
onClose = onClose || function (code, message) {
182+
console.log(`[WebSocket] closed: ${code} - ${message}`);
183+
};
184+
onError = onError || function (err) {
185+
console.log('[WebSocket] error: ' + err);
186+
};
187+
wss.on('connection', function (ws) {
188+
let location = url.parse(ws.upgradeReq.url, true);
189+
console.log('[WebSocketServer] connection: ' + location.href);
190+
191+
ws.on('message', onMessage);
192+
ws.on('close', onClose);
193+
ws.on('error', onError);
194+
195+
if (location.pathname !== '/ws/chat') {
196+
// close ws:
197+
ws.close(4000, 'Invalid URL');
198+
}
199+
// check user:
200+
let user = parseUser(ws.upgradeReq);
201+
if (!user) {
202+
ws.close(4001, 'Invalid user');
203+
}
204+
ws.user = user;
205+
ws.wss = wss;
206+
onConnection.apply(ws);
207+
});
208+
209+
console.log('WebSocketServer was attached.');
210+
return wss;
211+
}
212+
213+
let messageIndex = 0;
214+
215+
function createMessage(type, user, data) {
216+
messageIndex++;
217+
return JSON.stringify({
218+
id: messageIndex,
219+
type: type,
220+
user: user,
221+
data: data
222+
});
223+
}
224+
225+
function onConnect() {
226+
let user = this.user;
227+
let msg = createMessage('join', user, `${user.name} joined.`);
228+
229+
this.wss.broadcast(msg);
230+
// build user list:
231+
let users = this.wss.clients.map(function (client) {
232+
return client.user;
233+
});
234+
this.send(createMessage('list', user, users));
235+
}
236+
237+
function onMessage() {
238+
console.log(message);
239+
240+
if (message && message.trim()) {
241+
let msg = createMessage('chat', this.user, message.trim());
242+
this.wss.broadcast(msg);
243+
}
244+
}
245+
246+
function onClose() {
247+
let user = this.user;
248+
let msg = createMessage('left', user, `${user.name} is left.`);
249+
this.wss.broadcast(msg);
250+
}
251+
252+
// module.exports = app;
253+
254+
app.wss = createWebSocketServer(server, onConnect, onMessage, onClose);
134255

135-
module.exports = app;
256+
console.log('app started at port 3000...');

js_notes/hello-koa/controllers/index.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,24 @@
55
*/
66
'use strict';
77

8+
// module.exports = {
9+
// 'GET /': async (ctx, next) => {
10+
// ctx.render('index.html', {
11+
// title: 'Welcome'
12+
// });
13+
// }
14+
// };
15+
816
module.exports = {
917
'GET /': async (ctx, next) => {
10-
ctx.render('index.html', {
11-
title: 'Welcome'
12-
});
18+
let user = ctx.state.user;
19+
20+
if (user) {
21+
ctx.render('room.html', {
22+
user: user
23+
});
24+
} else {
25+
ctx.response.redirect('/signin');
26+
}
1327
}
1428
};

js_notes/hello-koa/controllers/signin.js

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,56 @@
55
*/
66
'use strict';
77

8+
// module.exports = {
9+
// 'POST /signin': async (ctx, next) => {
10+
// let
11+
// email = ctx.request.body.email || '',
12+
// password = ctx.request.body.password || '';
13+
//
14+
// if (email === '[email protected]' && password === '123456') {
15+
// console.log('signin ok!');
16+
// ctx.render('signin-ok.html', {
17+
// title: 'Sign In Ok',
18+
// name: 'Mr Node'
19+
// });
20+
// } else {
21+
// console.log('signin failed!');
22+
// ctx.render('signin-failed.html', {
23+
// title: 'Sign In Failed'
24+
// });
25+
// }
26+
// }
27+
// };
28+
29+
let index = 0;
30+
831
module.exports = {
32+
'GET /signin': async (ctx, next) => {
33+
let names = '甲乙丙丁戊己庚辛壬癸';
34+
let name = names[index % 10];
35+
36+
ctx.render('signin.html', {
37+
name: `路人${name}`
38+
});
39+
},
40+
941
'POST /signin': async (ctx, next) => {
10-
let
11-
email = ctx.request.body.email || '',
12-
password = ctx.request.body.password || '';
42+
index++;
43+
let name = ctx.request.body.name || '路人甲';
44+
let user = {
45+
id: index,
46+
name: name,
47+
image: index % 10
48+
};
49+
let value = Buffer.from(JSON.stringify(user)).toString('base64');
50+
51+
console.log(`Set cookie value: ${value}`);
52+
ctx.cookies.set('name', value);
53+
ctx.response.redirect('/');
54+
},
1355

14-
if (email === '[email protected]' && password === '123456') {
15-
console.log('signin ok!');
16-
ctx.render('signin-ok.html', {
17-
title: 'Sign In Ok',
18-
name: 'Mr Node'
19-
});
20-
} else {
21-
console.log('signin failed!');
22-
ctx.render('signin-failed.html', {
23-
title: 'Sign In Failed'
24-
});
25-
}
56+
'GET /signout': async (ctx, next) => {
57+
ctx.cookies.set('name', '');
58+
ctx.response.redirect('/signin');
2659
}
2760
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
server {
2+
listen 80;
3+
server_name localhost;
4+
5+
gzip on;
6+
gzip_min_length 1024;
7+
gzip_buffers 4 8k;
8+
gzip_types text/css application/x-javascript application/json;
9+
10+
sendfile on;
11+
12+
location ^~ /static/ {
13+
root /path/to/hello-koa;
14+
}
15+
16+
location ^~ /ws/ {
17+
proxy_pass http://127.0.0.1:3000;
18+
proxy_http_version 1.1;
19+
proxy_set_header Upgrade $http_upgrade;
20+
proxy_set_header Connection "upgrade";
21+
}
22+
23+
location / {
24+
proxy_pass http://127.0.0.1:3000;
25+
proxy_set_header X-Real-IP $remote_addr;
26+
proxy_set_header Host $host;
27+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
28+
}
29+
}

0 commit comments

Comments
 (0)