Skip to content

Instantly share code, notes, and snippets.

@Cacodaimon
Created October 22, 2012 17:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cacodaimon/3932968 to your computer and use it in GitHub Desktop.
Save Cacodaimon/3932968 to your computer and use it in GitHub Desktop.
WebSocket nodejs server & client tutorial used @ cacodaemon.de
module.exports.Client = function (name, socket) {
this.name = name
this.socket = socket
this.send = function (msg) {
this.socket.send(msg)
}
this.toString = function (msg) {
return this.name
}
}
var Client = require('./client.js').Client
module.exports.Clients = function () {
var clients = new Array()
var clientCounter = 0
this.sendToClient = function (client, msg) {
try {
client.send(msg)
}
catch (error) {
console.log(error)
if (error == 'Error: not opened') {
this.removeClient(null, client.name)
}
}
}
this.forEachClient = function (callBack) {
for (var i = clients.length - 1; i >= 0; i--) {
if (!clients[i]) {
clients.splice(i, 1)
continue
}
callBack(clients[i], i)
}
}
this.getClientByName = function (name) {
for (var i = clients.length - 1; i >= 0; i--) {
if (clients[i].name == name) {
return clients[i]
}
}
return null
}
this.getClientBySocket = function (socket) {
for (var i = clients.length - 1; i >= 0; i--) {
if (clients[i].socket == socket) {
return clients[i]
}
}
return null
}
this.addClient = function (socket) {
var client = new Client('User_' + ++clientCounter, socket)
clients.push(client)
this.sendToClient(client, '/welcome ' + client)
this.sendToAll('/users ' + clients.join(' '))
return client
}
this.removeClient = function (socket, name) {
var removedClients = new Array()
for (var i = clients.length - 1; i >= 0; i--) {
if (socket && clients[i].socket == socket) {
removedClients.push(clients[i])
clients.splice(i, 1)
}
if (name && clients[i].name == name) {
removedClients.push(clients[i])
clients.splice(i, 1)
}
}
for (var i = removedClients.length - 1; i >= 0; i--) {
this.sendToAll('/removed ' + removedClients[i])
}
}
this.sendToAll = function (msg) {
var thath = this
this.forEachClient(function (client, i) {
thath.sendToClient(client, msg)
})
}
this.sendToAllFromClient = function (msg, socket) {
var sender = this.getClientBySocket(socket)
var thath = this
this.forEachClient(function (client, i) {
if (sender == client) {
return
}
thath.sendToClient(client, sender + ': ' + msg)
})
}
this.command = function (msg, socket) {
if (msg.substr(0, 1) != '/') {
return false
}
var client = this.getClientBySocket(socket)
var params = msg.split(' ')
var type = params[0]
params.splice(0, 1)
switch (type) {
case '/name':
if (!params[0]) {
return false
}
var oldName = client.name
client.name = params[0]
this.sendToAll('/name_change ' + oldName + ' ' + client.name)
break
case '/private':
if (params.length < 2) {
return false
}
var reciever = this.getClientByName(params[0])
params.splice(0, 1)
var privateMsg = '/private ' + client.name + ': ' + params.join(' ')
this.sendToClient(reciever, privateMsg)
this.sendToClient(client, privateMsg)
break
}
return true
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Caco's Websocket Chat</title>
<link rel="stylesheet" href="screen.css" />
</head>
<body>
<header class="center">
<hgroup>
<h1>Caco's Websocket Chat</h1>
</hgroup>
</header>
<nav>
</nav>
<div class="center">
<section id="chat">
<ul id="chat_area"></ul>
<form id="char_form">
<fieldset>
<input type="text" name="chat_input" value="" id="chat_input"/>
</fieldset>
</form>
</section>
<section id="users">
<ul id="users_area"></ul>
</section>
</div>
<footer class="center">
<p>A tutorial by <a href="http://www.cacodaemon.de">Cacodaemon</a></p>
</footer>
</body>
<script type="text/javascript" src="websocket-client.js"></script>
</html>
.center {
margin-left: auto;
margin-right: auto;
width: 800px
}
ul {
margin: 0;
padding: 0;
list-style-type: none
}
fieldset {
border: 0
}
input {
border: 1px solid black;
width: 100%
}
footer {
clear: both
}
#chat {
width: 600px;
float: left
}
#users {
width: 200px;
float: left
}
#chat_area {
height: 200px;
overflow-y: scroll
}
#users_area {
height: 200px
}
.public {
background-color: #B5D045
}
.private {
background-color: #F47E7D
}
.own {
background-color: #66CCCC
}
function $ (elementId) { return document.getElementById(elementId) }
var webSocket = new WebSocket('ws://localhost:1337')
var chatArea = $('chat_area')
var chatForm = $('char_form')
var chatInput = $('chat_input')
var usersArea = $('users_area')
var messageCounter = 0
var myName = null
function addMessage (msg, type) {
var newMessage = document.createElement('li')
newMessage.textContent = newMessage.innerText = msg
newMessage.setAttribute('id', 'msg_' + messageCounter)
newMessage.setAttribute('class', type)
chatArea.appendChild(newMessage)
chatArea.scrollTop = chatArea.scrollHeight
if (messageCounter > 20) {
oldMessage = $('msg_' + (messageCounter - 21))
chatArea.removeChild(oldMessage)
}
messageCounter++
}
function addUser (users) {
for (var i = users.length - 1; i >= 0; i--) {
var userName = users[i]
if ($('user_' + userName)) {
continue
}
var newUser = document.createElement('li')
newUser.textContent = newUser.innerText = userName
newUser.setAttribute('id', 'user_' + userName)
if (myName == userName) {
newUser.setAttribute('class', 'own')
}
newUser.onclick = function () {
if (this.getAttribute('class') == 'own') {
webSocket.send('/name ' + prompt('Enter new nick name: ', myName))
}
else {
webSocket.send('/private ' + this.innerText + ' ' + prompt('Enter private message to: ' + this.innerText, ''))
}
}
usersArea.appendChild(newUser)
}
}
function changeUserName (from, to) {
var user = $('user_' + from);
user.textContent = user.innerText = to
user.setAttribute('id', 'user_' + to)
if (from == myName) {
myName = to
}
}
function removeUser (userName) {
usersArea.removeChild($('user_' + userName))
}
function privateMessage (message) {
addMessage(message, 'private')
}
function command(msg) {
if (msg.substr(0, 1) != '/') {
return false
}
var params = msg.split(' ')
var type = params[0]
params.splice(0, 1)
switch (type) {
case '/users':
addUser(params)
break
case '/name_change':
changeUserName(params[0], params[1])
break
case '/removed':
removeUser(params)
break
case '/private':
privateMessage(params.join(' '))
break
case '/welcome':
myName = params[0]
break
}
return true
}
webSocket.onmessage = function (msg) {
if (command(msg.data)) {
return
}
addMessage(msg.data, 'public')
}
chatForm.onsubmit = function(form) {
if (chatInput.value == '') {
return false
}
webSocket.send(chatInput.value)
addMessage(chatInput.value, 'own')
chatInput.value = ''
return false
}
var WebSocketServer = new require('ws').Server
var webSocketServer = new WebSocketServer({port: 1337})
var Clients = new require('./clients.js').Clients
var clients = new Clients()
webSocketServer.on('connection', function(webSocket) {
console.log('new connection')
clients.addClient(webSocket)
webSocket.on('message', function(msg) {
console.log('incomming msg from: ' + clients.getClientBySocket(webSocket) + ' (' + msg + ')')
if (clients.command(msg, webSocket)) {
return
}
clients.sendToAllFromClient(msg, webSocket)
})
webSocket.on('close', function() {
console.log('closed connection')
})
})
var http = require('http');
var fs = require('fs');
var mime = new Array()
mime.css = 'text/css'
mime.html = 'text/html'
mime.js = 'text/javascript'
http.createServer(function (req, res) {
if (req.url == '/') {
req.url = '/index.html'
}
var fileType = req.url.split('.')[1]
console.log(mime[fileType])
fs.readFile('Client/' + req.url, function (err, data) {
if (err) {
res.writeHead(404, {'Content-Type': 'text/html'});
res.end('<h1>404</h1><h2>File: ' + req.url + ' not found!</h2>');
}
else if (data) {
res.writeHead(200, {'Content-Type': mime[fileType]});
res.end(data);
}
});
}).listen(8080, '127.0.0.1');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment