Skip to content

Instantly share code, notes, and snippets.

@jdrydn
Last active May 19, 2016 12:33
Show Gist options
  • Save jdrydn/58c2ee4d8a15c407316e4925f0d3d309 to your computer and use it in GitHub Desktop.
Save jdrydn/58c2ee4d8a15c407316e4925f0d3d309 to your computer and use it in GitHub Desktop.
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.js"></script>
<script>
var successFn = function (res) {
if (!res || !res.token) throw new Error('NO TOKEN');
console.log('Thanks for logging in, ' + name);
var socket = io();
socket.on('connect', function () {
socket.emit('authenticate', {
token: res.token
});
});
socket.on('error', function(err) {
if (err.type == 'UnauthorizedError' || err.code == 'invalid_token') {
// redirect user to login page perhaps?
console.log('User\'s token has expired');
}
console.log(err);
});
socket.on('authenticated', function () {
console.log('Thanks for authenticating, ' + name);
$('form').submit(function() {
socket.emit('send', {
text: $('#m').val()
});
appendMessage({
author: name,
text: $('#m').val()
});
$('#m').val('');
return false;
});
socket.on('message', function (data) {
appendMessage(data);
});
$.ajax({
dataType: 'json',
url: '/messages',
success: function (res) {
if (res && Array.isArray(res.messages)) {
$('#messages').html('');
res.messages.forEach(function (data) {
appendMessage(data);
});
}
}
});
});
var appendMessage = function (data) {
$('#messages').append($('<li>').text((data.author || 'Anon') + ': ' + data.text));
};
};
$(document).ready(function () {
var name = prompt('ENTER YOUR NAME');
if (!name) {
alert('Without a name, you cannot chat');
throw new Error('No name provided');
}
console.log('HEY ' + name);
$.ajax({
method: 'POST',
url: '/login',
headers: {
'Content-Type': 'application/json'
},
dataType: 'json',
data: JSON.stringify({
name: name
}),
success: successFn
});
});
</script>
</body>
</html>
{
"env": {
"DEBUG": "SOCKET:*",
"NODE_ENV": "development"
},
"ext": "js json hbs yml",
"ignore": [
"coverage",
"node_modules"
]
}
{
"name": "SOCKET-MOFO",
"version": "0.1.0",
"main": "sockets.js",
"dependencies": {
"body-parser": "^1.15.1",
"connect-redis": "^3.0.2",
"debug": "^2.2.0",
"express": "^4.13.4",
"express-session": "^1.13.0",
"hiredis": "^0.4.1",
"morgan": "^1.7.0",
"redis": "^2.6.0-2",
"socket.io": "^1.4.6",
"socketio-jwt": "^4.3.4"
}
}
var bodyParser = require('body-parser');
var debug = require('debug')('SOCKET:Server');
var express = require('express');
var http = require('http');
var jwt = require('jsonwebtoken');
var morgan = require('morgan');
var path = require('path');
var redis = require('redis');
var socketIO = require('socket.io');
var socketioJwt = require('socketio-jwt');
var app = express();
var redisClient = redis.createClient();
var redisSubscriber = redis.createClient();
var server = http.createServer(app);
var io = socketIO(server);
//app.use(bodyParser.json({ limit: '1mb' }));
//app.use(bodyParser.urlencoded({ extended: true }));
app.use(morgan('tiny'));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
});
app.post('/login', bodyParser.json({ limit: '1mb' }), function (req, res, next) {
var token = jwt.sign(req.body, 'window-between-diameter-expression', {
algorithm: 'HS256',
noTimestamp: true
});
res.json({
token: token,
payload: req.body
});
});
app.get('/messages', function (req, res, next) {
redisClient.lrange('chat:messages', 0, -1, function (err, messages) {
if (err) return next(err);
res.json(messages.map(function (message) {
return JSON.parse(message);
}));
});
});
io.sockets.on('connection', socketioJwt.authorize({
algorithm: 'HS256',
secret: 'window-between-diameter-expression',
timeout: 15000, // 15 seconds to send the authentication message
// additional_auth: function (token, resolveFn, rejectFn) {
// console.log('Hooray!', token);
// resolveFn();
// }
}));
io.sockets.on('authenticated', function (socket) {
// Subscribe to the Redis channel
redisSubscriber.subscribe('ChatChannel');
console.log(socket.decoded_token);
// Handle incoming messages
socket.on('send', function (data) {
debug('IN', socket.decoded_token, data);
data.author = socket.decoded_token.name || 'Anon';
// Publish it
redisClient.publish('ChatChannel', JSON.stringify(data));
// Persist it to a Redis list
redisClient.rpush('chat:messages', JSON.stringify(data));
});
// Handle receiving messages from the PubSub-pipe
var newMessage = function (channel, data) {
debug('OUT', socket.decoded_token, channel, data);
data = JSON.parse(data);
// If this data is for this user, then send it to them
if (data.author !== socket.decoded_token.name) {
socket.emit('message', data);
}
};
redisSubscriber.on('message', newMessage);
socket.on('disconnect', function () {
redisSubscriber.removeListener('message', newMessage);
});
});
server.listen(4000, '0.0.0.0', function () {
console.log('Listening on %s:%d', server.address().address, server.address().port);
});

A Friday Project of Sockets

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment