Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #################################################################
- # Main chat module that handles all socket communication #
- # routines and messages via Socket.io library. #
- # #
- # Distinguishes two type of sockets - user sockets and #
- # moderator socket which are handled differently. User socket #
- # can only send and receive messages to/from moderator's #
- # socket. Moderator's socket can perform many more actions: #
- # - start/end chat #
- # - users moderation (allowing/disallowing connected #
- # socket to join discussion) #
- # - banning users #
- # - broadcast messages #
- # #
- # Inivitations feature is also available - in this case #
- # only sockets with valid invitatinon hash will be #
- # allowed to connect and join chat. #
- #################################################################
- # required modules
- crypto = require 'crypto'
- config = require './config'
- db = require './db'
- buffer = require './buffer'
- shared = require './shared'
- # moderator socket connected flag
- exports.moderated = false
- # spawn socket engine
- exports.spawn = (app) ->
- # get socket.io
- sio = require('socket.io').listen app
- # moderator socket referene
- socket_moderator = null
- # users' sockets buffer
- sockets = {}
- # expired invites buffer
- expired_invites = {}
- # bans buffer
- bans =
- addresses: {}
- nicks: {}
- # on socket connection
- sio.sockets.on 'connection', (socket) ->
- ### Events/messages handlers ###
- # moderator socket sign-in routine #
- signModerator = (err, chat) ->
- # set nick to chat's main guest name
- socket.set 'nick', chat.person, ->
- # extracts nick from sockets buffer #
- getClients = (moderated = true) ->
- clients = for id, client of sockets when client.moderated is moderated
- { id: id, nick: client.nick }
- # put socket into chat room
- socket.join 'chat'
- # mark socket as moderator socket
- socket.set 'moderator', true
- # send connected sockets list, chat events and chat progress to moderator
- socket.emit 'mod connected',
- clients:
- moderated: getClients true
- unmoderated: getClients false
- progress: buffer.read 'chat'
- events: buffer.read 'events'
- # socket sign-in routine #
- sign = (id, nick, invited = false) ->
- # socket allowed flag
- allowed = true
- # if socket with invitation hash
- if invited
- # if invitation expired
- if expired_invites.hasOwnProperty id
- # emit message
- socket.emit 'invitation expired'
- # disconnect socket
- socket.disconnect()
- # disallow socket
- allowed = false
- else
- # put into expired invitations
- expired_invites[id] = null
- # if socket allowed
- if allowed
- # store socket reference in sockets buffer
- sockets[id] =
- socket: socket
- nick: nick
- moderated: invited
- # set socket's moderated flag
- socket.set 'moderated', invited
- # put socket into chat room
- socket.join 'chat'
- # emit sign-in operation confirmation message
- socket.emit 'user signed', invited: invited
- buffer.write shared.messages.sign(nick: nick), 'events'
- # if moderator socket connected
- if socket_moderator?
- # emit socket sign-in event
- socket_moderator.emit 'mod user signed',
- id: id
- nick: nick
- allowed
- # socket moderation routine #
- moderateClient = (client, invited = false) ->
- # set socket's moderated flag
- sockets[client].moderated = true
- # get socket reference
- socket = sockets[client].socket
- # set socket moderated flag
- socket.set 'moderated', true, ->
- # emit moderation confirmation message
- socket.emit 'user moderated',
- # send chat progress to connected socket
- progress: buffer.read 'chat'
- if invited and socket_moderator?
- socket_moderator.emit 'user invited moderated',
- id: client
- # bulk moderation #
- moderateBulk = (payload) ->
- moderateClient client for client in payload.clients
- clients = for key, id of payload.clients
- sockets[id].nick
- buffer.write shared.messages.moderateBulk(clients), 'events'
- # sends sockets chat message to moderator socket #
- clientMessage = (payload) ->
- # get sender nick
- socket.get 'id', (err, id) ->
- buffer.write shared.messages.clientMessage({nick: sockets[id].nick, message: payload.message}), 'events'
- # if success and moderator socket connected
- if not err and id and socket_moderator?
- # emit message and payload
- socket_moderator.emit 'mod user message',
- id: id
- message: payload.message
- # socket disconnection routine #
- disconnectClient = (err, id) ->
- # if success and socket in sockets buffer
- if not err and id and sockets[id]?
- buffer.write shared.messages.disconnectClient(nick: sockets[id].nick), 'events'
- # remove socket from buffer
- delete sockets[id]
- # if moderator socket connected
- if socket_moderator?
- # emit disconnect message
- socket_moderator.emit 'mod user unsigned',
- id: id
- # chat closure routine #
- close = ->
- # broadcast closure message
- socket_moderator.broadcast.emit 'mod close'
- # forced sockets disconnect
- for id, client of sockets
- client.socket.disconnect()
- # empty buffers buffer
- sockets = {}
- expired_invites = {}
- bans =
- addresses: {}
- nicks: {}
- # save chat data
- db.saveChat (chat) ->
- id = chat._id
- delete chat._id
- chat.active = false
- chat.started = false
- chat.history = buffer.read 'chat'
- buffer.wipe()
- id
- # performs chat database quasi-locking routine #
- start = ->
- # save flag in database
- db.saveChat (chat) ->
- id = chat._id
- delete chat._id
- chat.started = true
- id
- # calculates message digest based on configured global hashing algorith
- digest = (message) ->
- hash = crypto.createHash config.app.hashing()
- hash.update message
- hash.digest 'hex'
- timestamp = ->
- dt = new Date()
- hours = parseInt dt.getHours()
- minutes = parseInt dt.getMinutes()
- seconds = parseInt dt.getSeconds()
- if hours < 10
- hours = "0#{hours}"
- if minutes < 10
- minutes = "0#{minutes}"
- if seconds < 10
- seconds = "0#{seconds}"
- "#{hours}:#{minutes}:#{seconds}"
- ban = (payload) ->
- for id, key in payload.clients
- bans.nicks[id] = true
- bans.addresses[sockets[id].socket.handshake.address.address] = true
- sockets[id].socket.emit 'user banned'
- sockets[id].socket.disconnect()
- delete sockets[id]
- ### Communication section ###
- # weak moderator socket discovery
- if socket.handshake.headers.referer.indexOf('chat/moderator') > 0
- # moderator socket connected flag
- exports.moderated = true
- # moderator socket reference
- socket_moderator = socket
- # call moderator sign-in routine
- db.getChat signModerator
- # moderator socket disconnect routine
- socket.on 'disconnect', ->
- # wipe moderator socket reference
- socket_moderator = null
- # moderator socket not connected flag
- exports.moderated = false
- # if moderator socket not discovered
- else
- db.getChat (err, chat) ->
- # if chat closed (access with invitations)
- if chat.closed
- # emit message
- socket.emit 'chat closed'
- # if chat opened
- else
- if bans.addresses.hasOwnProperty socket.handshake.address.address
- socket.emit 'user banned'
- else
- socket.get 'id', (err, id) ->
- # if socket not already signed-in
- if not err and not id
- # put socket in purgatory (moderator's waiting room)
- socket.join 'purgatory'
- # emit message
- socket.emit 'user unsigned'
- # calls socket disconnect routine
- socket.on 'disconnect', ->
- socket.get 'id', disconnectClient
- # handles socket invitation request routine
- socket.on 'invitation', (payload) ->
- db.getChat (err, chat) ->
- # validate invitation
- if chat.invites.hasOwnProperty payload.invitation
- # get nick assigned to invitation
- nick = chat.invites[payload.invitation]
- id = digest nick
- # set assigned nick
- socket.set 'id', id, ->
- # call socket sign-in routine
- if sign id, nick, true
- # call socket moderate routine
- moderateClient id, true
- else
- socket.emit 'invitation invalid'
- # handles socket manual sign-in routine
- socket.on 'user sign', (payload) ->
- id = digest payload.nick
- # check against nicks ban list
- if bans.nicks.hasOwnProperty id
- socket.emit 'user nick banned'
- # if nick already binded to different socket
- else if sockets.hasOwnProperty id
- socket.emit 'user nick invalid'
- else
- socket.set 'id', id, ->
- # call socket sign-in routine
- sign id, payload.nick
- # handles moderator socket asked question broadcast routine
- socket.on 'mod question', (payload) ->
- payload.time = timestamp()
- # write payload to chat's buffer
- buffer.write payload, 'chat'
- # broadcast payload
- socket_moderator.broadcast.emit 'mod user question', payload
- # handles moderator socket message broadcast routine
- socket.on 'mod message', (payload) ->
- # store moderator socket reference
- sock = socket_moderator
- sock.get 'nick', (err, nick) ->
- # get moderator socket nick
- payload.nick = nick
- payload.time = timestamp()
- # write payload to chat's buffer
- buffer.write payload, 'chat'
- # broadcast payload
- sock.broadcast.emit 'mod answer', payload
- # bind handlers to events
- socket.on 'mod moderate', moderateBulk
- socket.on 'mod ban', ban
- socket.on 'user message', clientMessage
- socket.on 'mod close', close
- socket.on 'mod start', start
- console.log 'Chat spawned'
Add Comment
Please, Sign In to add comment