Created
August 9, 2012 01:40
-
-
Save nov/3300227 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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