Skip to content

Instantly share code, notes, and snippets.

@nov
Created August 9, 2012 01:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nov/3300227 to your computer and use it in GitHub Desktop.
Save nov/3300227 to your computer and use it in GitHub Desktop.
fs = require 'fs'
util = require 'util'
url = require 'url'
ws = require 'ws'
redis = require 'redis'
Sequelize = require 'sequelize'
restler = require 'restler'
# Config
port = process.env.PORT || 80
env = process.env.NODE_ENV || 'development'
pwd = process.env.PWD
loadConfig = (filename) ->
JSON.parse(
fs.readFileSync "/#{pwd}/config/#{filename}.json", 'utf-8'
)[env]
config =
mysql: loadConfig('mysql')
redis: loadConfig('redis')
ws: loadConfig('ws')
api: loadConfig('api')
# Setup MySQL (for fetching access tokens)
sequelize = new Sequelize config.mysql.database, config.mysql.username, config.mysql.password,
host: config.mysql.host
port: config.mysql.port || 3306
# Setup Redis Pub/Sub Subscriber (for receiving messages from Rails)
subscriber = redis.createClient config.redis.port, config.redis.host
if pass = config.redis.pass
subscriber.auth pass, ->
console.log 'redis subscriber authenticated'
# Define AccessToken Model
AccessToken = sequelize.define 'access_token',
token: Sequelize.STRING
user_id: Sequelize.INTEGER
, underscored: true
# Setup Server
sockets = []
wss = new ws.Server
host: '0.0.0.0'
port: port
disconnected = (socket) ->
delete sockets[socket.user_id]
util.debug "socket##{socket.user_id || 'unauthenticated'} closed"
wss.on 'connection', (socket) ->
util.debug 'connection opened'
# Assuming access_token is included in query part.
# TODO: Should use HTTP Authorization header in near future.
endpoint = url.parse socket.upgradeReq.url, true
token = endpoint.query.access_token
util.debug "token: #{token}"
# Setting-up Rails API client with given access_token.
# NOTE: This app just pass incoming messages to Rails via HTTP Post
API = restler.service (token) ->
@defaults.headers =
'Authorization': "Bearer #{token}"
return
, {baseURL: config.api.base_url}
, seen: (post_id) ->
@post "/posts/#{post_id}/reaction"
api = new API(token)
# Receiving WebSocket message from Clients
socket.on 'message', (message) ->
util.debug "message: #{message}"
message = JSON.parse(message)
post_id = message.post_id
console.log api
api.seen(post_id)
.on 'complete', (data) ->
console.info data
socket.on 'close', ->
disconnected socket
socket.on 'error', (error) ->
disconnected socket
util.debug error.message
socket.respond_with = (response) ->
socket.send JSON.stringify(response)
db_error = (error) ->
util.error error.message
socket.respond_with
status: 'error'
type: 'system'
message: 'DB Error'
unauthenticated = ->
util.error 'Unauthorized'
socket.respond_with
status: 'error'
type: 'system'
message: 'Unauthorized'
socket.close()
# Authenticate users using access_token and bind the user_id to socket itself.
authenticate = (token) ->
AccessToken.find
where:
token: token
.success (access_token) ->
if access_token
socket.user_id = access_token.user_id
sockets[access_token.user_id] = socket
socket.respond_with
status: 'success'
type: 'system'
message: 'Authenticated'
else
unauthenticated()
.failure (error) ->
db_error error
authenticate token
# Start Subscribing Redis Pub/Sub
channel = 'oauth-socket-sample-channel'
subscriber.subscribe channel
subscriber.on 'message', (message, recipients) ->
for user_id in recipients
sockets[user_id]?.send message, ->
disconnected sockets[user_id]
# Run Socket Server
console.log "running at port #{port} in #{env}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment