Rewrite of web socket event backend.
This commit is contained in:
parent
08c2a59569
commit
5f74e50433
27 changed files with 309 additions and 279 deletions
|
@ -20,10 +20,10 @@ class Index extends App.ControllerContent
|
|||
params = @formParam(e.target)
|
||||
App.Event.trigger(
|
||||
'ws:send'
|
||||
action: 'broadcast'
|
||||
event: 'session:maintenance'
|
||||
spool: false
|
||||
data: params
|
||||
event: 'broadcast'
|
||||
data:
|
||||
event: 'session:maintenance'
|
||||
data: params
|
||||
)
|
||||
@notify
|
||||
type: 'success'
|
||||
|
|
|
@ -7,7 +7,7 @@ class Widget extends App.Controller
|
|||
'session:maintenance'
|
||||
(data) =>
|
||||
console.log('session:maintenance', data)
|
||||
@showMessage( data )
|
||||
@showMessage(data)
|
||||
'maintenance'
|
||||
)
|
||||
|
||||
|
@ -19,8 +19,8 @@ class Widget extends App.Controller
|
|||
button = 'Close'
|
||||
|
||||
# convert to html and linkify
|
||||
message.message = App.Utils.textCleanup( message.message )
|
||||
message.message = App.Utils.text2html( message.message )
|
||||
message.message = App.Utils.textCleanup(message.message)
|
||||
message.message = App.Utils.text2html(message.message)
|
||||
|
||||
new App.SessionMessage(
|
||||
head: message.head
|
||||
|
@ -32,4 +32,4 @@ class Widget extends App.Controller
|
|||
forceReload: message.reload
|
||||
)
|
||||
|
||||
App.Config.set( 'maintenance', Widget, 'Widgets' )
|
||||
App.Config.set('maintenance', Widget, 'Widgets')
|
|
@ -142,7 +142,7 @@ class App.OnlineNotificationWidget extends App.Controller
|
|||
@alreadyShown[item.id] = true
|
||||
if @fetchedData
|
||||
word = "#{item.type}d"
|
||||
title = "#{item.created_by.displayName()} #{App.i18n.translateInline(word)} #{App.i18n.translateInline(item.object_name)} #{item.title}"
|
||||
title = "#{item.created_by.displayName()} #{App.i18n.translateInline(word)} #{App.i18n.translateInline(item.object_name)} \"#{item.title}\""
|
||||
@notifyDesktop(
|
||||
url: item.link
|
||||
title: title
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class Widget extends App.Controller
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@bind()
|
||||
|
@ -14,13 +13,14 @@ class Widget extends App.Controller
|
|||
|
||||
# broadcast to other browser instance
|
||||
App.WebSocket.send(
|
||||
action: 'broadcast'
|
||||
event: 'session:takeover'
|
||||
event: 'broadcast'
|
||||
spool: true
|
||||
recipient:
|
||||
user_id: [ App.Session.get( 'id' ) ]
|
||||
data:
|
||||
taskbar_id: App.TaskManager.TaskbarId()
|
||||
event: 'session:takeover'
|
||||
data:
|
||||
taskbar_id: App.TaskManager.TaskbarId()
|
||||
)
|
||||
'maintenance'
|
||||
)
|
||||
|
@ -51,4 +51,4 @@ class Widget extends App.Controller
|
|||
'maintenance'
|
||||
)
|
||||
|
||||
App.Config.set( 'session_taken_over', Widget, 'Widgets' )
|
||||
App.Config.set('session_taken_over', Widget, 'Widgets')
|
||||
|
|
|
@ -68,7 +68,7 @@ class _webSocketSingleton extends App.Controller
|
|||
|
||||
# get spool messages after successful ws login
|
||||
App.Event.bind(
|
||||
'ws:login', (data) =>
|
||||
'ws:login', =>
|
||||
@spool()
|
||||
'ws'
|
||||
)
|
||||
|
@ -106,7 +106,7 @@ class _webSocketSingleton extends App.Controller
|
|||
if @ws.readyState isnt 1
|
||||
@queue.push data
|
||||
else
|
||||
string = JSON.stringify( data )
|
||||
string = JSON.stringify(data)
|
||||
@ws.send(string)
|
||||
|
||||
auth: (data) =>
|
||||
|
@ -114,7 +114,7 @@ class _webSocketSingleton extends App.Controller
|
|||
|
||||
# logon websocket
|
||||
data =
|
||||
action: 'login'
|
||||
event: 'login'
|
||||
session_id: App.Config.get('session_id')
|
||||
fingerprint: App.Browser.fingerprint()
|
||||
@send(data)
|
||||
|
@ -125,7 +125,7 @@ class _webSocketSingleton extends App.Controller
|
|||
|
||||
# build data to send to server
|
||||
data =
|
||||
action: 'spool'
|
||||
event: 'spool'
|
||||
if @lastSpoolMessage
|
||||
data['timestamp'] = @lastSpoolMessage
|
||||
|
||||
|
@ -137,10 +137,7 @@ class _webSocketSingleton extends App.Controller
|
|||
App.Delay.set reset, 60000, 'reset-spool-sent-finished-if-not-returned', 'ws'
|
||||
|
||||
# ask for spool messages
|
||||
App.Event.trigger(
|
||||
'ws:send'
|
||||
data
|
||||
)
|
||||
@send(data)
|
||||
|
||||
close: ( params = {} ) =>
|
||||
if params['force']
|
||||
|
@ -154,7 +151,7 @@ class _webSocketSingleton extends App.Controller
|
|||
return if @backend is 'ajax'
|
||||
|
||||
@log 'debug', 'send websocket ping'
|
||||
@send( { action: 'ping' } )
|
||||
@send(event: 'ping')
|
||||
|
||||
# check if ping is back within 2 min
|
||||
App.Delay.clear 'websocket-ping-check', 'ws'
|
||||
|
@ -166,10 +163,10 @@ class _webSocketSingleton extends App.Controller
|
|||
pong: ->
|
||||
return if @backend is 'ajax'
|
||||
|
||||
@log 'debug', 'received websocket ping'
|
||||
@log 'debug', 'received websocket pong'
|
||||
|
||||
# test again after 1 min
|
||||
App.Delay.set @ping, 60000, 'websocket-pong', 'ws'
|
||||
App.Delay.set(@ping, 60000, 'websocket-pong', 'ws')
|
||||
|
||||
connect: =>
|
||||
|
||||
|
@ -216,10 +213,10 @@ class _webSocketSingleton extends App.Controller
|
|||
@queue = []
|
||||
|
||||
# send ping to check connection
|
||||
App.Delay.set @ping, 60000, 'websocket-send-ping-to-heck-connection', 'ws'
|
||||
App.Delay.set(@ping, 60000, 'websocket-send-ping-to-heck-connection', 'ws')
|
||||
|
||||
@ws.onmessage = (e) =>
|
||||
pipe = JSON.parse( e.data )
|
||||
pipe = JSON.parse(e.data)
|
||||
@log 'debug', 'ws:onmessage', pipe
|
||||
@_receiveMessage(pipe)
|
||||
|
||||
|
@ -271,28 +268,20 @@ class _webSocketSingleton extends App.Controller
|
|||
|
||||
# go through all blocks
|
||||
for item in data
|
||||
@log 'debug', 'onmessage', item
|
||||
|
||||
# set timestamp to get spool messages later
|
||||
if item['spool']
|
||||
@lastSpoolMessage = Math.round( +new Date()/1000 )
|
||||
|
||||
# reset reconnect loop
|
||||
if item['action'] is 'pong'
|
||||
if item['event'] is 'pong'
|
||||
@pong()
|
||||
|
||||
# fill collection
|
||||
if item['collection']
|
||||
@log 'debug', 'onmessage collection:' + item['collection']
|
||||
|
||||
# fire event
|
||||
if item['event']
|
||||
if typeof item['event'] is 'object'
|
||||
for event in item['event']
|
||||
@log 'debug', 'onmessage event:' + event
|
||||
App.Event.trigger( event, item['data'] )
|
||||
else
|
||||
@log 'debug', 'onmessage event:' + item['event']
|
||||
App.Event.trigger( item['event'], item['data'] )
|
||||
@log 'debug', "onmessage event: #{item['event']}"
|
||||
App.Event.trigger(item['event'], item['data'])
|
||||
|
||||
_ajaxInit: (data = {}) =>
|
||||
|
||||
|
@ -304,7 +293,7 @@ class _webSocketSingleton extends App.Controller
|
|||
id: 'ws-login'
|
||||
type: 'POST'
|
||||
url: @Config.get('api_path') + '/message_send'
|
||||
data: JSON.stringify({ data: { action: 'login' } })
|
||||
data: JSON.stringify(data: { event: 'login' })
|
||||
processData: false
|
||||
queue: false
|
||||
success: (data) =>
|
||||
|
@ -319,8 +308,8 @@ class _webSocketSingleton extends App.Controller
|
|||
|
||||
# try reconnect on error after x sec.
|
||||
reconnect = =>
|
||||
@_ajaxInit( force: true )
|
||||
App.Delay.set reconnect, 10000, '_ajaxInit-reconnect-on-error', 'ws'
|
||||
@_ajaxInit(force: true)
|
||||
App.Delay.set(reconnect, 10000, '_ajaxInit-reconnect-on-error', 'ws')
|
||||
)
|
||||
|
||||
_ajaxSend: (data) =>
|
||||
|
@ -338,7 +327,7 @@ class _webSocketSingleton extends App.Controller
|
|||
App.Ajax.request(
|
||||
type: 'POST'
|
||||
url: @Config.get('api_path') + '/message_send'
|
||||
data: JSON.stringify({ client_id: @client_id, data: data })
|
||||
data: JSON.stringify(client_id: @client_id, data: data)
|
||||
processData: false
|
||||
queue: true
|
||||
success: (data) =>
|
||||
|
@ -358,19 +347,19 @@ class _webSocketSingleton extends App.Controller
|
|||
id: 'message_receive',
|
||||
type: 'POST'
|
||||
url: @Config.get('api_path') + '/message_receive'
|
||||
data: JSON.stringify({ client_id: @client_id })
|
||||
data: JSON.stringify(client_id: @client_id)
|
||||
processData: false
|
||||
success: (data) =>
|
||||
@log 'debug', 'ajax:onmessage', data
|
||||
@_receiveMessage(data)
|
||||
if data && data.error
|
||||
@client_id = undefined
|
||||
@_ajaxInit( force: true )
|
||||
@_ajaxInit(force: true)
|
||||
@_ajaxReceiveWorking = false
|
||||
@_ajaxReceive()
|
||||
error: (data) =>
|
||||
@client_id = undefined
|
||||
@_ajaxInit( force: true )
|
||||
@_ajaxInit(force: true)
|
||||
@_ajaxReceiveWorking = false
|
||||
)
|
||||
|
||||
|
|
|
@ -17,77 +17,31 @@ class LongPollingController < ApplicationController
|
|||
if !params['data']
|
||||
params['data'] = {}
|
||||
end
|
||||
session_data = {}
|
||||
if current_user.id
|
||||
session_data = { 'id' => current_user.id }
|
||||
end
|
||||
|
||||
# spool messages for new connects
|
||||
if params['data']['spool']
|
||||
msg = JSON.generate( params['data'] )
|
||||
Sessions.spool_create(msg)
|
||||
Sessions.spool_create(params['data'])
|
||||
end
|
||||
|
||||
# get spool messages and send them to new client connection
|
||||
if params['data']['action'] == 'spool'
|
||||
|
||||
# error handling
|
||||
if params['data']['timestamp']
|
||||
log "request spool data > '#{Time.zone.at( params['data']['timestamp'] )}'", client_id
|
||||
else
|
||||
log 'request spool init data', client_id
|
||||
if params['data']['event'] == 'login'
|
||||
Sessions.create(client_id, session_data, { type: 'ajax' })
|
||||
elsif params['data']['event']
|
||||
message = Sessions::Event.run(
|
||||
event: params['data']['event'],
|
||||
payload: params['data'],
|
||||
session: session_data,
|
||||
client_id: client_id,
|
||||
clients: {},
|
||||
options: {},
|
||||
)
|
||||
if message
|
||||
Sessions.send(client_id, message)
|
||||
end
|
||||
|
||||
if current_user
|
||||
spool = Sessions.spool_list( params['data']['timestamp'], current_user.id )
|
||||
spool.each { |item|
|
||||
if item[:type] == 'direct'
|
||||
log "send spool to (user_id=#{current_user.id})", client_id
|
||||
Sessions.send( client_id, item[:message] )
|
||||
else
|
||||
log 'send spool', client_id
|
||||
Sessions.send( client_id, item[:message] )
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# send spool:sent event to client
|
||||
sleep 0.2
|
||||
log 'send spool:sent event', client_id
|
||||
Sessions.send( client_id, { event: 'spool:sent', data: { timestamp: Time.zone.now.utc.to_i } } )
|
||||
end
|
||||
|
||||
# receive message
|
||||
if params['data']['action'] == 'login'
|
||||
user_id = session[:user_id]
|
||||
user = {}
|
||||
if user_id
|
||||
user = User.find( user_id ).attributes
|
||||
end
|
||||
log "send auth login (user_id #{user_id})", client_id
|
||||
Sessions.create( client_id, user, { type: 'ajax' } )
|
||||
|
||||
# broadcast
|
||||
elsif params['data']['action'] == 'broadcast'
|
||||
|
||||
# list all current clients
|
||||
client_list = Sessions.list
|
||||
client_list.each {|local_client_id, local_client|
|
||||
if local_client_id != client_id
|
||||
|
||||
# broadcast to recipient list
|
||||
if params['data']['recipient'] && params['data']['recipient']['user_id']
|
||||
params['data']['recipient']['user_id'].each { |loop_user_id|
|
||||
if local_client[:user]['id'].to_s == loop_user_id.to_s
|
||||
log "send broadcast from (#{client_id}) to (user_id #{loop_user_id})", local_client_id
|
||||
Sessions.send( local_client_id, params['data'] )
|
||||
end
|
||||
}
|
||||
# broadcast every client
|
||||
else
|
||||
log "send broadcast from (#{client_id})", local_client_id
|
||||
Sessions.send( local_client_id, params['data'] )
|
||||
end
|
||||
else
|
||||
log 'do not send broadcast to it self', client_id
|
||||
end
|
||||
}
|
||||
else
|
||||
log "unknown message '#{params['data'].inspect}'", client_id
|
||||
end
|
||||
|
||||
if new_connection
|
||||
|
@ -116,13 +70,16 @@ class LongPollingController < ApplicationController
|
|||
sleep 0.25
|
||||
}
|
||||
#sleep 1
|
||||
Sessions.touch( client_id )
|
||||
Sessions.touch(client_id)
|
||||
|
||||
# set max loop time to 24 sec. because of 30 sec. timeout of mod_proxy
|
||||
count = 12
|
||||
count = 3
|
||||
if Rails.env.production?
|
||||
count = 12
|
||||
end
|
||||
loop do
|
||||
count = count - 1
|
||||
queue = Sessions.queue( client_id )
|
||||
queue = Sessions.queue(client_id)
|
||||
if queue && queue[0]
|
||||
logger.debug "send #{queue.inspect} to #{client_id}"
|
||||
render json: queue
|
||||
|
@ -133,7 +90,7 @@ class LongPollingController < ApplicationController
|
|||
}
|
||||
#sleep 2
|
||||
if count == 0
|
||||
render json: { action: 'pong' }
|
||||
render json: { event: 'pong' }
|
||||
return
|
||||
end
|
||||
end
|
||||
|
@ -154,7 +111,7 @@ class LongPollingController < ApplicationController
|
|||
def client_id_verify
|
||||
return if !params[:client_id]
|
||||
sessions = Sessions.sessions
|
||||
return if !sessions.include?( params[:client_id].to_s )
|
||||
return if !sessions.include?(params[:client_id].to_s)
|
||||
params[:client_id].to_s
|
||||
end
|
||||
|
||||
|
|
|
@ -427,10 +427,11 @@ returns
|
|||
FileUtils.rm_rf path
|
||||
end
|
||||
|
||||
def self.spool_create(msg)
|
||||
def self.spool_create(data)
|
||||
msg = JSON.generate(data)
|
||||
path = "#{@path}/spool/"
|
||||
FileUtils.mkpath path
|
||||
file_path = path + "/#{Time.now.utc.to_f}-#{rand(99_999)}"
|
||||
file_path = "#{path}/#{Time.now.utc.to_f}-#{rand(99_999)}"
|
||||
File.open( file_path, 'wb' ) { |file|
|
||||
data = {
|
||||
msg: msg,
|
||||
|
@ -483,18 +484,27 @@ returns
|
|||
|
||||
next if current_user_id != user_id
|
||||
|
||||
message = message_parsed
|
||||
if message_parsed['event'] == 'broadcast'
|
||||
message = message_parsed['data']
|
||||
end
|
||||
|
||||
item = {
|
||||
type: 'direct',
|
||||
message: message_parsed,
|
||||
message: message,
|
||||
}
|
||||
data.push item
|
||||
}
|
||||
|
||||
# spool to every client
|
||||
else
|
||||
message = message_parsed
|
||||
if message_parsed['event'] == 'broadcast'
|
||||
message = message_parsed['data']
|
||||
end
|
||||
item = {
|
||||
type: 'broadcast',
|
||||
message: message_parsed,
|
||||
message: message,
|
||||
}
|
||||
data.push item
|
||||
end
|
||||
|
|
|
@ -80,7 +80,7 @@ class Sessions::Backend::Collections::Base
|
|||
@client.log "push assets for push_collection #{items.first.class} for user #{@user.id}"
|
||||
@client.send(
|
||||
data: assets,
|
||||
event: [ 'loadAssets' ],
|
||||
event: 'loadAssets',
|
||||
)
|
||||
|
||||
@client.log "push push_collection #{items.first.class} for user #{@user.id}"
|
||||
|
|
|
@ -58,7 +58,7 @@ class Sessions::Backend::TicketOverviewIndex
|
|||
|
||||
@client.log "push overview_index for user #{@user.id}"
|
||||
@client.send(
|
||||
event: ['ticket_overview_index'],
|
||||
event: 'ticket_overview_index',
|
||||
data: data,
|
||||
)
|
||||
end
|
||||
|
|
|
@ -107,7 +107,7 @@ class Sessions::Backend::TicketOverviewList
|
|||
# send update to browser
|
||||
@client.send(
|
||||
data: assets,
|
||||
event: [ 'loadAssets' ]
|
||||
event: 'loadAssets'
|
||||
)
|
||||
@client.send(
|
||||
data: {
|
||||
|
@ -120,7 +120,7 @@ class Sessions::Backend::TicketOverviewList
|
|||
owner_id: [],
|
||||
},
|
||||
},
|
||||
event: [ 'ticket_overview_rebuild' ],
|
||||
event: 'ticket_overview_rebuild',
|
||||
)
|
||||
end
|
||||
}
|
||||
|
|
|
@ -1,28 +1,18 @@
|
|||
class Sessions::Event
|
||||
include ApplicationLib
|
||||
|
||||
def self.run(event, data, session, client_id)
|
||||
adapter = "Sessions::Event::#{event.to_classname}"
|
||||
def self.run(params)
|
||||
adapter = "Sessions::Event::#{params[:event].to_classname}"
|
||||
|
||||
begin
|
||||
backend = load_adapter(adapter)
|
||||
rescue => e
|
||||
return { error: "No such event #{event}" }
|
||||
return { error: "No such event #{params[:event]}" }
|
||||
end
|
||||
|
||||
ActiveRecord::Base.establish_connection
|
||||
instance = backend.new(data, session, client_id)
|
||||
pre = instance.pre
|
||||
if pre
|
||||
ActiveRecord::Base.remove_connection
|
||||
return pre
|
||||
end
|
||||
instance = backend.new(params)
|
||||
result = instance.run
|
||||
post = instance.post
|
||||
if post
|
||||
ActiveRecord::Base.remove_connection
|
||||
return post
|
||||
end
|
||||
instance.destroy
|
||||
result
|
||||
end
|
||||
|
||||
|
|
44
lib/sessions/event/base.rb
Normal file
44
lib/sessions/event/base.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
class Sessions::Event::Base
|
||||
|
||||
def initialize(params)
|
||||
params.each { |key, value|
|
||||
instance_variable_set "@#{key}", value
|
||||
}
|
||||
|
||||
@is_web_socket = false
|
||||
return if !@clients[@client_id]
|
||||
@is_web_socket = true
|
||||
end
|
||||
|
||||
def websocket_send(recipient_client_id, data)
|
||||
if data.class != Array
|
||||
msg = "[#{data.to_json}]"
|
||||
else
|
||||
msg = data.to_json
|
||||
end
|
||||
if @clients[recipient_client_id]
|
||||
log 'debug', "ws send #{msg}", recipient_client_id
|
||||
@clients[recipient_client_id][:websocket].send(msg)
|
||||
else
|
||||
log 'debug', "fs send #{msg}", recipient_client_id
|
||||
Sessions.send(recipient_client_id, data)
|
||||
end
|
||||
end
|
||||
|
||||
def log(level, data, client_id = nil)
|
||||
if !@options[:v]
|
||||
return if level == 'debug'
|
||||
end
|
||||
if !client_id
|
||||
client_id = @client_id
|
||||
end
|
||||
# rubocop:disable Rails/Output
|
||||
puts "#{Time.now.utc.iso8601}:client(#{client_id}) #{data}"
|
||||
#puts "#{Time.now.utc.iso8601}:#{ level }:client(#{ client_id }) #{ data }"
|
||||
# rubocop:enable Rails/Output
|
||||
end
|
||||
|
||||
def destroy
|
||||
end
|
||||
|
||||
end
|
45
lib/sessions/event/broadcast.rb
Normal file
45
lib/sessions/event/broadcast.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
class Sessions::Event::Broadcast < Sessions::Event::Base
|
||||
|
||||
def run
|
||||
|
||||
# list all current clients
|
||||
client_list = Sessions.list
|
||||
client_list.each {|local_client_id, local_client|
|
||||
if local_client_id == @client_id
|
||||
log 'notice', 'do not send broadcast to it self'
|
||||
next
|
||||
end
|
||||
|
||||
# broadcast to recipient list
|
||||
if @payload['recipient']
|
||||
if @payload['recipient'].class != Hash
|
||||
log 'error', "recipient attribute isn't a hash '#{@payload['recipient'].inspect}'"
|
||||
else
|
||||
if !@payload['recipient'].key?('user_id')
|
||||
log 'error', "need recipient.user_id attribute '#{@payload['recipient'].inspect}'"
|
||||
else
|
||||
if @payload['recipient']['user_id'].class != Array
|
||||
log 'error', "recipient.user_id attribute isn't an array '#{@payload['recipient']['user_id'].inspect}'"
|
||||
else
|
||||
@payload['recipient']['user_id'].each { |user_id|
|
||||
|
||||
next if local_client[:user]['id'].to_i != user_id.to_i
|
||||
|
||||
log 'notice', "send broadcast from (#{@client_id}) to (user_id=#{user_id})", local_client_id
|
||||
websocket_send(local_client_id, @payload['data'])
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# broadcast every client
|
||||
else
|
||||
log 'notice', "send broadcast from (#{@client_id})", local_client_id
|
||||
websocket_send(local_client_id, @payload['data'])
|
||||
end
|
||||
}
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
end
|
|
@ -1,11 +1,12 @@
|
|||
class Sessions::Event::ChatAgentState < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
return super if super
|
||||
|
||||
# check if user has permissions
|
||||
return if !agent_permission_check
|
||||
|
||||
Chat::Agent.state(@session['id'], @data['data']['active'])
|
||||
Chat::Agent.state(@session['id'], @payload['data']['active'])
|
||||
|
||||
# broadcast new state to agents
|
||||
broadcast_agent_state_update(@session['id'])
|
||||
|
@ -14,8 +15,9 @@ class Sessions::Event::ChatAgentState < Sessions::Event::ChatBase
|
|||
event: 'chat_agent_state',
|
||||
data: {
|
||||
state: 'ok',
|
||||
active: @data['data']['active'],
|
||||
active: @payload['data']['active'],
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
class Sessions::Event::ChatBase
|
||||
class Sessions::Event::ChatBase < Sessions::Event::Base
|
||||
|
||||
def initialize(data, session, client_id)
|
||||
@data = data
|
||||
@session = session
|
||||
@client_id = client_id
|
||||
def initialize(params)
|
||||
super(params)
|
||||
return if !@is_web_socket
|
||||
ActiveRecord::Base.establish_connection
|
||||
end
|
||||
|
||||
def pre
|
||||
def destroy
|
||||
return if !@is_web_socket
|
||||
ActiveRecord::Base.remove_connection
|
||||
end
|
||||
|
||||
def run
|
||||
|
||||
# check if feature is enabled
|
||||
return if Setting.get('chat')
|
||||
|
@ -18,10 +23,6 @@ class Sessions::Event::ChatBase
|
|||
}
|
||||
end
|
||||
|
||||
def post
|
||||
false
|
||||
end
|
||||
|
||||
def broadcast_agent_state_update(ignore_user_id = nil)
|
||||
|
||||
# send broadcast to agents
|
||||
|
@ -99,11 +100,11 @@ class Sessions::Event::ChatBase
|
|||
end
|
||||
|
||||
def current_chat_session
|
||||
Chat::Session.find_by(session_id: @data['data']['session_id'])
|
||||
Chat::Session.find_by(session_id: @payload['data']['session_id'])
|
||||
end
|
||||
|
||||
def check_chat_session_exists
|
||||
if !@data['data'] || !@data['data']['session_id']
|
||||
if !@payload['data'] || !@payload['data']['session_id']
|
||||
error = {
|
||||
event: 'chat_error',
|
||||
data: {
|
||||
|
@ -117,7 +118,7 @@ class Sessions::Event::ChatBase
|
|||
error = {
|
||||
event: 'chat_error',
|
||||
data: {
|
||||
state: "No such session id #{@data['data']['session_id']}",
|
||||
state: "No such session id #{@payload['data']['session_id']}",
|
||||
},
|
||||
}
|
||||
Sessions.send(@client_id, error)
|
||||
|
@ -125,7 +126,7 @@ class Sessions::Event::ChatBase
|
|||
end
|
||||
|
||||
def current_chat
|
||||
Chat.find_by(id: @data['data']['chat_id'])
|
||||
Chat.find_by(id: @payload['data']['chat_id'])
|
||||
end
|
||||
|
||||
def check_chat_exists
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
return super if super
|
||||
|
||||
return if !check_chat_session_exists
|
||||
|
||||
|
@ -57,4 +58,5 @@ class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase
|
|||
},
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
class Sessions::Event::ChatSessionInit < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
return super if super
|
||||
return if !check_chat_exists
|
||||
|
||||
# create chat session
|
||||
chat_session = Chat::Session.create(
|
||||
chat_id: @data['data']['chat_id'],
|
||||
chat_id: @payload['data']['chat_id'],
|
||||
name: '',
|
||||
state: 'waiting',
|
||||
preferences: {
|
||||
|
@ -26,4 +27,5 @@ class Sessions::Event::ChatSessionInit < Sessions::Event::ChatBase
|
|||
},
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class Sessions::Event::ChatSessionLeaveTemporary < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
return super if super
|
||||
return if !check_chat_session_exists
|
||||
chat_session = current_chat_session
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class Sessions::Event::ChatSessionMessage < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
return super if super
|
||||
return if !check_chat_session_exists
|
||||
chat_session = current_chat_session
|
||||
|
||||
|
@ -10,7 +11,7 @@ class Sessions::Event::ChatSessionMessage < Sessions::Event::ChatBase
|
|||
end
|
||||
chat_message = Chat::Message.create(
|
||||
chat_session_id: chat_session.id,
|
||||
content: @data['data']['content'],
|
||||
content: @payload['data']['content'],
|
||||
created_by_id: user_id,
|
||||
)
|
||||
message = {
|
||||
|
@ -35,4 +36,5 @@ class Sessions::Event::ChatSessionMessage < Sessions::Event::ChatBase
|
|||
}
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
return super if super
|
||||
agent_permission_check
|
||||
|
||||
# find first in waiting list
|
||||
|
@ -48,4 +49,5 @@ class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase
|
|||
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class Sessions::Event::ChatSessionTyping < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
return super if super
|
||||
return if !check_chat_session_exists
|
||||
chat_session = current_chat_session
|
||||
|
||||
|
@ -28,4 +29,5 @@ class Sessions::Event::ChatSessionTyping < Sessions::Event::ChatBase
|
|||
},
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class Sessions::Event::ChatStatusAgent < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
return super if super
|
||||
|
||||
# check if user has permissions
|
||||
return if !agent_permission_check
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
class Sessions::Event::ChatStatusCustomer < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
return super if super
|
||||
return if !check_chat_exists
|
||||
|
||||
# check if it's a chat sessin reconnect
|
||||
session_id = nil
|
||||
if @data['data']['session_id']
|
||||
session_id = @data['data']['session_id']
|
||||
if @payload['data']['session_id']
|
||||
session_id = @payload['data']['session_id']
|
||||
|
||||
# update recipients of existing sessions
|
||||
chat_session = Chat::Session.find_by(session_id: session_id)
|
||||
|
@ -17,4 +18,5 @@ class Sessions::Event::ChatStatusCustomer < Sessions::Event::ChatBase
|
|||
data: current_chat.customer_state(session_id),
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
32
lib/sessions/event/login.rb
Normal file
32
lib/sessions/event/login.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
class Sessions::Event::Login < Sessions::Event::Base
|
||||
|
||||
def run
|
||||
|
||||
# get user_id
|
||||
if @payload && @payload['session_id']
|
||||
if @is_web_socket
|
||||
ActiveRecord::Base.establish_connection
|
||||
end
|
||||
session = ActiveRecord::SessionStore::Session.find_by(session_id: @payload['session_id'])
|
||||
if @is_web_socket
|
||||
ActiveRecord::Base.remove_connection
|
||||
end
|
||||
end
|
||||
|
||||
if session && session.data && session.data['user_id']
|
||||
new_session_data = { 'id' => session.data['user_id'] }
|
||||
else
|
||||
new_session_data = {}
|
||||
end
|
||||
|
||||
if @clients[@client_id]
|
||||
@clients[@client_id][:session] = new_session_data
|
||||
Sessions.create(@client_id, new_session_data, { type: 'websocket' })
|
||||
else
|
||||
Sessions.create(@client_id, new_session_data, { type: 'ajax' })
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
end
|
9
lib/sessions/event/ping.rb
Normal file
9
lib/sessions/event/ping.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
class Sessions::Event::Ping < Sessions::Event::Base
|
||||
|
||||
def run
|
||||
{
|
||||
event: 'pong',
|
||||
}
|
||||
end
|
||||
|
||||
end
|
41
lib/sessions/event/spool.rb
Normal file
41
lib/sessions/event/spool.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
class Sessions::Event::Spool < Sessions::Event::Base
|
||||
|
||||
# get spool messages and send them to new client connection
|
||||
def run
|
||||
|
||||
# error handling
|
||||
if @payload['timestamp']
|
||||
log 'notice', "request spool data > '#{Time.at(@payload['timestamp']).utc.iso8601}'"
|
||||
else
|
||||
log 'notice', 'request spool with init data'
|
||||
end
|
||||
|
||||
if !@session || !@session['id']
|
||||
log 'error', "can't send spool, session not authenticated"
|
||||
return
|
||||
end
|
||||
|
||||
spool = Sessions.spool_list(@payload['timestamp'], @session['id'])
|
||||
spool.each { |item|
|
||||
|
||||
# create new msg to push to client
|
||||
if item[:type] == 'direct'
|
||||
log 'notice', "send spool to (user_id=#{@session['id']})"
|
||||
websocket_send(@client_id, item[:message])
|
||||
else
|
||||
log 'notice', 'send spool'
|
||||
websocket_send(@client_id, item[:message])
|
||||
end
|
||||
}
|
||||
|
||||
# send spool:sent event to client
|
||||
log 'notice', 'send spool:sent event'
|
||||
{
|
||||
event: 'spool:sent',
|
||||
data: {
|
||||
timestamp: Time.now.utc.to_i,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
end
|
|
@ -122,7 +122,7 @@ EventMachine.run {
|
|||
@clients.delete client_id
|
||||
end
|
||||
|
||||
Sessions.destory( client_id )
|
||||
Sessions.destory(client_id)
|
||||
}
|
||||
|
||||
# manage messages
|
||||
|
@ -145,128 +145,24 @@ EventMachine.run {
|
|||
|
||||
# spool messages for new connects
|
||||
if data['spool']
|
||||
Sessions.spool_create(msg)
|
||||
Sessions.spool_create(data)
|
||||
end
|
||||
|
||||
# get spool messages and send them to new client connection
|
||||
if data['action'] == 'spool'
|
||||
|
||||
# error handling
|
||||
if data['timestamp']
|
||||
log 'notice', "request spool data > '#{Time.at(data['timestamp']).utc.iso8601}'", client_id
|
||||
else
|
||||
log 'notice', 'request spool with init data', client_id
|
||||
end
|
||||
|
||||
if @clients[client_id] && @clients[client_id][:session] && @clients[client_id][:session]['id']
|
||||
spool = Sessions.spool_list( data['timestamp'], @clients[client_id][:session]['id'] )
|
||||
spool.each { |item|
|
||||
|
||||
# create new msg to push to client
|
||||
if item[:type] == 'direct'
|
||||
log 'notice', "send spool to (user_id=#{@clients[client_id][:session]['id']})", client_id
|
||||
websocket_send(client_id, item[:message])
|
||||
else
|
||||
log 'notice', 'send spool', client_id
|
||||
websocket_send(client_id, item[:message])
|
||||
end
|
||||
}
|
||||
else
|
||||
log 'error', "can't send spool, session not authenticated", client_id
|
||||
end
|
||||
|
||||
# send spool:sent event to client
|
||||
log 'notice', 'send spool:sent event', client_id
|
||||
message = {
|
||||
event: 'spool:sent',
|
||||
data: {
|
||||
timestamp: Time.now.utc.to_i,
|
||||
},
|
||||
}
|
||||
websocket_send(client_id, message)
|
||||
end
|
||||
|
||||
# get session
|
||||
if data['action'] == 'login'
|
||||
|
||||
# get user_id
|
||||
if data && data['session_id']
|
||||
ActiveRecord::Base.establish_connection
|
||||
session = ActiveRecord::SessionStore::Session.find_by( session_id: data['session_id'] )
|
||||
ActiveRecord::Base.remove_connection
|
||||
end
|
||||
|
||||
if session && session.data && session.data['user_id']
|
||||
new_session_data = { 'id' => session.data['user_id'] }
|
||||
else
|
||||
new_session_data = {}
|
||||
end
|
||||
|
||||
@clients[client_id][:session] = new_session_data
|
||||
|
||||
Sessions.create( client_id, new_session_data, { type: 'websocket' } )
|
||||
|
||||
# remember ping, send pong back
|
||||
elsif data['action'] == 'ping'
|
||||
message = {
|
||||
action: 'pong',
|
||||
}
|
||||
websocket_send(client_id, message)
|
||||
|
||||
# broadcast
|
||||
elsif data['action'] == 'broadcast'
|
||||
|
||||
# list all current clients
|
||||
client_list = Sessions.list
|
||||
client_list.each {|local_client_id, local_client|
|
||||
if local_client_id != client_id
|
||||
|
||||
# broadcast to recipient list
|
||||
if data['recipient']
|
||||
if data['recipient'].class != Hash
|
||||
log 'error', "recipient attribute isn't a hash '#{data['recipient'].inspect}'"
|
||||
else
|
||||
if !data['recipient'].key?('user_id')
|
||||
log 'error', "need recipient.user_id attribute '#{data['recipient'].inspect}'"
|
||||
else
|
||||
if data['recipient']['user_id'].class != Array
|
||||
log 'error', "recipient.user_id attribute isn't an array '#{data['recipient']['user_id'].inspect}'"
|
||||
else
|
||||
data['recipient']['user_id'].each { |user_id|
|
||||
|
||||
next if local_client[:user]['id'].to_i != user_id.to_i
|
||||
|
||||
log 'notice', "send broadcast from (#{client_id}) to (user_id=#{user_id})", local_client_id
|
||||
if local_client[:meta][:type] == 'websocket' && @clients[ local_client_id ]
|
||||
websocket_send(local_client_id, data)
|
||||
else
|
||||
Sessions.send(local_client_id, data)
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# broadcast every client
|
||||
else
|
||||
log 'notice', "send broadcast from (#{client_id})", local_client_id
|
||||
if local_client[:meta][:type] == 'websocket' && @clients[ local_client_id ]
|
||||
websocket_send(local_client_id, data)
|
||||
else
|
||||
Sessions.send(local_client_id, data)
|
||||
end
|
||||
end
|
||||
else
|
||||
log 'notice', 'do not send broadcast to it self', client_id
|
||||
end
|
||||
}
|
||||
|
||||
elsif data['event']
|
||||
log 'notice', "execute event '#{data['event']}'", client_id
|
||||
message = Sessions::Event.run(data['event'], data, @clients[client_id][:session], client_id)
|
||||
if data['event']
|
||||
log 'debug', "execute event '#{data['event']}'", client_id
|
||||
message = Sessions::Event.run(
|
||||
event: data['event'],
|
||||
payload: data,
|
||||
session: @clients[client_id][:session],
|
||||
client_id: client_id,
|
||||
clients: @clients,
|
||||
options: @options,
|
||||
)
|
||||
if message
|
||||
websocket_send(client_id, message)
|
||||
end
|
||||
else
|
||||
log 'error', "unknown message '#{data.inspect}'", client_id
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -375,7 +271,7 @@ EventMachine.run {
|
|||
}
|
||||
end
|
||||
|
||||
def log( level, data, client_id = '-' )
|
||||
def log(level, data, client_id = '-')
|
||||
if !@options[:v]
|
||||
return if level == 'debug'
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue