Guest User

Untitled

a guest
May 21st, 2018
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #################################################################
  2. # Main chat module that handles all socket communication        #
  3. # routines and messages via Socket.io library.                  #
  4. #                                                               #
  5. # Distinguishes two type of sockets - user sockets and          #
  6. # moderator socket which are handled differently. User socket   #
  7. # can only send and receive messages to/from moderator's        #
  8. # socket. Moderator's socket can perform many more actions:     #
  9. # - start/end chat                                              #
  10. # - users moderation (allowing/disallowing connected            #
  11. #   socket to join discussion)                                  #
  12. # - banning users                                               #
  13. # - broadcast messages                                          #
  14. #                                                               #
  15. # Inivitations feature is also available - in this case         #
  16. # only sockets with valid invitatinon hash will be              #
  17. # allowed to connect and join chat.                             #
  18. #################################################################
  19.  
  20. # required modules
  21. crypto = require 'crypto'
  22. config = require './config'
  23. db = require './db'
  24. buffer = require './buffer'
  25. shared = require './shared'
  26.  
  27. # moderator socket connected flag
  28. exports.moderated = false
  29.  
  30. # spawn socket engine
  31. exports.spawn = (app) ->
  32.     # get socket.io
  33.     sio = require('socket.io').listen app
  34.    
  35.     # moderator socket referene
  36.     socket_moderator = null
  37.    
  38.     # users' sockets buffer
  39.     sockets = {}
  40.    
  41.     # expired invites buffer
  42.     expired_invites = {}
  43.    
  44.     # bans buffer
  45.     bans =
  46.         addresses: {}
  47.         nicks: {}
  48.  
  49.     # on socket connection
  50.     sio.sockets.on 'connection', (socket) ->
  51.         ### Events/messages handlers ###
  52.        
  53.         # moderator socket sign-in routine #
  54.         signModerator = (err, chat) ->
  55.            
  56.             # set nick to chat's main guest name
  57.             socket.set 'nick', chat.person, ->
  58.                 # extracts nick from sockets buffer #
  59.                 getClients = (moderated = true) ->
  60.                     clients = for id, client of sockets when client.moderated is moderated
  61.                         { id: id, nick: client.nick }
  62.                    
  63.                 # put socket into chat room
  64.                 socket.join 'chat'
  65.                
  66.                 # mark socket as moderator socket
  67.                 socket.set 'moderator', true
  68.                
  69.                 # send connected sockets list, chat events and chat progress to moderator
  70.                 socket.emit 'mod connected',
  71.                     clients:
  72.                         moderated: getClients true
  73.                         unmoderated: getClients false
  74.                     progress: buffer.read 'chat'
  75.                     events: buffer.read 'events'
  76.                
  77.         # socket sign-in routine #
  78.         sign = (id, nick, invited = false) ->
  79.             # socket allowed flag
  80.             allowed = true
  81.            
  82.             # if socket with invitation hash
  83.             if invited
  84.                 # if invitation expired
  85.                 if expired_invites.hasOwnProperty id
  86.                     # emit message
  87.                     socket.emit 'invitation expired'
  88.                    
  89.                     # disconnect socket
  90.                     socket.disconnect()
  91.                    
  92.                     # disallow socket
  93.                     allowed = false
  94.                 else
  95.                     # put into expired invitations
  96.                     expired_invites[id] = null
  97.            
  98.             # if socket allowed
  99.             if allowed
  100.                 # store socket reference in sockets buffer
  101.                 sockets[id] =
  102.                     socket: socket
  103.                     nick: nick
  104.                     moderated: invited
  105.  
  106.                 # set socket's moderated flag
  107.                 socket.set 'moderated', invited
  108.                
  109.                 # put socket into chat room
  110.                 socket.join 'chat'
  111.                
  112.                 # emit sign-in operation confirmation message
  113.                 socket.emit 'user signed', invited: invited
  114.                
  115.                 buffer.write shared.messages.sign(nick: nick), 'events'
  116.  
  117.                 # if moderator socket connected
  118.                 if socket_moderator?
  119.                     # emit socket sign-in event
  120.                     socket_moderator.emit 'mod user signed',
  121.                         id: id
  122.                         nick: nick
  123.            
  124.             allowed
  125.            
  126.         # socket moderation routine #
  127.         moderateClient = (client, invited = false) ->
  128.             # set socket's moderated flag
  129.             sockets[client].moderated = true
  130.            
  131.             # get socket reference
  132.             socket = sockets[client].socket
  133.            
  134.             # set socket moderated flag
  135.             socket.set 'moderated', true, ->
  136.                 # emit moderation confirmation message
  137.                 socket.emit 'user moderated',
  138.                     # send chat progress to connected socket
  139.                     progress: buffer.read 'chat'
  140.                
  141.                 if invited and socket_moderator?
  142.                     socket_moderator.emit 'user invited moderated',
  143.                         id: client
  144.        
  145.         # bulk moderation #
  146.         moderateBulk = (payload) ->
  147.             moderateClient client for client in payload.clients
  148.            
  149.             clients = for key, id of payload.clients
  150.                 sockets[id].nick
  151.                
  152.             buffer.write shared.messages.moderateBulk(clients), 'events'
  153.        
  154.         # sends sockets chat message to moderator socket #
  155.         clientMessage = (payload) ->
  156.             # get sender nick
  157.             socket.get 'id', (err, id) ->
  158.                 buffer.write shared.messages.clientMessage({nick: sockets[id].nick, message: payload.message}), 'events'
  159.                
  160.                 # if success and moderator socket connected
  161.                 if not err and id and socket_moderator?
  162.                     # emit message and payload
  163.                     socket_moderator.emit 'mod user message',
  164.                         id: id
  165.                         message: payload.message
  166.  
  167.         # socket disconnection routine #
  168.         disconnectClient = (err, id) ->
  169.             # if success and socket in sockets buffer
  170.             if not err and id and sockets[id]?         
  171.                 buffer.write shared.messages.disconnectClient(nick: sockets[id].nick), 'events'
  172.                
  173.                 # remove socket from buffer
  174.                 delete sockets[id]
  175.                
  176.                 # if moderator socket connected
  177.                 if socket_moderator?
  178.                     # emit disconnect message
  179.                     socket_moderator.emit 'mod user unsigned',
  180.                         id: id
  181.                        
  182.         # chat closure routine #
  183.         close = ->
  184.             # broadcast closure message
  185.             socket_moderator.broadcast.emit 'mod close'
  186.  
  187.             # forced sockets disconnect
  188.             for id, client of sockets
  189.                 client.socket.disconnect()
  190.            
  191.             # empty buffers buffer
  192.             sockets = {}
  193.             expired_invites = {}
  194.             bans =
  195.                 addresses: {}
  196.                 nicks: {}
  197.            
  198.             # save chat data
  199.             db.saveChat (chat) ->
  200.                 id = chat._id
  201.                 delete chat._id
  202.  
  203.                 chat.active = false
  204.                 chat.started = false
  205.                 chat.history = buffer.read 'chat'
  206.                
  207.                 buffer.wipe()
  208.                 id
  209.  
  210.         # performs chat database quasi-locking routine #
  211.         start = ->
  212.             # save flag in database
  213.             db.saveChat (chat) ->
  214.                 id = chat._id
  215.                 delete chat._id
  216.  
  217.                 chat.started = true
  218.                
  219.                 id
  220.  
  221.         # calculates message digest based on configured global hashing algorith
  222.         digest = (message) ->
  223.             hash = crypto.createHash config.app.hashing()
  224.             hash.update message
  225.             hash.digest 'hex'
  226.            
  227.         timestamp = ->
  228.             dt = new Date()
  229.             hours =  parseInt dt.getHours()
  230.             minutes = parseInt dt.getMinutes()
  231.             seconds = parseInt dt.getSeconds()
  232.  
  233.             if hours < 10
  234.                 hours = "0#{hours}"
  235.             if minutes < 10
  236.                 minutes = "0#{minutes}"
  237.             if seconds < 10
  238.                 seconds = "0#{seconds}"
  239.  
  240.             "#{hours}:#{minutes}:#{seconds}"
  241.            
  242.         ban = (payload) ->
  243.             for id, key in payload.clients
  244.                 bans.nicks[id] = true
  245.                 bans.addresses[sockets[id].socket.handshake.address.address] = true
  246.                
  247.                 sockets[id].socket.emit 'user banned'
  248.                 sockets[id].socket.disconnect()
  249.                 delete sockets[id]
  250.                
  251.         ### Communication section ###
  252.        
  253.         # weak moderator socket discovery
  254.         if socket.handshake.headers.referer.indexOf('chat/moderator') > 0
  255.             # moderator socket connected flag
  256.             exports.moderated = true
  257.            
  258.             # moderator socket reference
  259.             socket_moderator = socket
  260.            
  261.             # call moderator sign-in routine
  262.             db.getChat signModerator
  263.            
  264.             # moderator socket disconnect routine
  265.             socket.on 'disconnect', ->
  266.                 # wipe moderator socket reference
  267.                 socket_moderator = null
  268.                
  269.                 # moderator socket not connected flag
  270.                 exports.moderated = false
  271.                
  272.         # if moderator socket not discovered
  273.         else
  274.             db.getChat (err, chat) ->
  275.                 # if chat closed (access with invitations)
  276.                 if chat.closed
  277.                     # emit message
  278.                     socket.emit 'chat closed'
  279.                 # if chat opened
  280.                 else
  281.                     if bans.addresses.hasOwnProperty socket.handshake.address.address
  282.                         socket.emit 'user banned'
  283.                     else
  284.                         socket.get 'id', (err, id) ->
  285.                             # if socket not already signed-in
  286.                             if not err and not id
  287.                                 # put socket in purgatory (moderator's waiting room)
  288.                                 socket.join 'purgatory'
  289.  
  290.                                 # emit message
  291.                                 socket.emit 'user unsigned'
  292.  
  293.             # calls socket disconnect routine
  294.             socket.on 'disconnect', ->
  295.                 socket.get 'id', disconnectClient
  296.  
  297.         # handles socket invitation request routine
  298.         socket.on 'invitation', (payload) ->
  299.             db.getChat (err, chat) ->
  300.                 # validate invitation
  301.                 if chat.invites.hasOwnProperty payload.invitation
  302.                     # get nick assigned to invitation
  303.                     nick = chat.invites[payload.invitation]
  304.                     id = digest nick
  305.                    
  306.                     # set assigned nick
  307.                     socket.set 'id', id, ->
  308.                         # call socket sign-in routine
  309.                         if sign id, nick, true
  310.                             # call socket moderate routine
  311.                             moderateClient id, true
  312.                 else
  313.                     socket.emit 'invitation invalid'
  314.        
  315.         # handles socket manual sign-in routine
  316.         socket.on 'user sign', (payload) ->
  317.             id = digest payload.nick
  318.            
  319.             # check against nicks ban list
  320.             if bans.nicks.hasOwnProperty id
  321.                 socket.emit 'user nick banned'
  322.             # if nick already binded to different socket
  323.             else if sockets.hasOwnProperty id
  324.                 socket.emit 'user nick invalid'
  325.             else
  326.                 socket.set 'id', id, ->
  327.                     # call socket sign-in routine
  328.                     sign id, payload.nick
  329.        
  330.         # handles moderator socket asked question broadcast routine
  331.         socket.on 'mod question', (payload) ->
  332.             payload.time = timestamp()
  333.            
  334.             # write payload to chat's buffer
  335.             buffer.write payload, 'chat'
  336.            
  337.             # broadcast payload
  338.             socket_moderator.broadcast.emit 'mod user question', payload
  339.            
  340.         # handles moderator socket message broadcast routine
  341.         socket.on 'mod message', (payload) ->
  342.             # store moderator socket reference
  343.             sock = socket_moderator
  344.             sock.get 'nick', (err, nick) ->
  345.                 # get moderator socket nick
  346.                 payload.nick = nick
  347.                 payload.time = timestamp()
  348.                
  349.                 # write payload to chat's buffer
  350.                 buffer.write payload, 'chat'
  351.                
  352.                 # broadcast payload
  353.                 sock.broadcast.emit 'mod answer', payload
  354.  
  355.         # bind handlers to events
  356.         socket.on 'mod moderate', moderateBulk
  357.         socket.on 'mod ban', ban
  358.         socket.on 'user message', clientMessage
  359.         socket.on 'mod close', close
  360.         socket.on 'mod start', start
  361.        
  362.     console.log 'Chat spawned'
Add Comment
Please, Sign In to add comment