long_polling_controller.rb 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class LongPollingController < ApplicationController
  3. skip_before_action :session_update # prevent race conditions
  4. prepend_before_action :authentication_check_only
  5. # GET /api/v1/message_send
  6. def message_send
  7. new_connection = false
  8. # check client id
  9. client_id = client_id_verify
  10. if !client_id
  11. new_connection = true
  12. client_id = client_id_gen
  13. log 'new client connection', client_id
  14. end
  15. data = params['data'].permit!.to_h
  16. session_data = {}
  17. if current_user&.id
  18. session_data = { 'id' => current_user.id }
  19. end
  20. if data['event'] == 'login'
  21. Sessions.create(client_id, session_data, { type: 'ajax' })
  22. elsif data['event']
  23. message = Sessions::Event.run(
  24. event: data['event'],
  25. payload: data,
  26. session: session_data,
  27. client_id: client_id,
  28. clients: {},
  29. options: {},
  30. )
  31. if message
  32. Sessions.send(client_id, message)
  33. end
  34. else
  35. log "unknown message '#{data.inspect}'", client_id
  36. end
  37. if new_connection
  38. result = { client_id: client_id }
  39. render json: result
  40. return
  41. end
  42. render json: {}
  43. end
  44. # GET /api/v1/message_receive
  45. def message_receive
  46. # check client id
  47. client_id = client_id_verify
  48. raise Exceptions::UnprocessableEntity, __('Invalid client_id received!') if !client_id
  49. # check queue to send
  50. begin
  51. # update last ping
  52. 4.times do
  53. sleep 0.25
  54. end
  55. # sleep 1
  56. Sessions.touch(client_id) # rubocop:disable Rails/SkipsModelValidations
  57. # set max loop time to 24 sec. because of 30 sec. timeout of mod_proxy
  58. count = 3
  59. if Rails.env.production?
  60. count = 12
  61. end
  62. loop do
  63. count -= 1
  64. queue = Sessions.queue(client_id)
  65. if queue && queue[0]
  66. logger.debug { "send #{queue.inspect} to #{client_id}" }
  67. render json: queue
  68. return
  69. end
  70. 8.times do
  71. sleep 0.25
  72. end
  73. # sleep 2
  74. if count.zero?
  75. render json: { event: 'pong' }
  76. return
  77. end
  78. end
  79. rescue
  80. raise Exceptions::UnprocessableEntity, __('Invalid client_id in receive loop!')
  81. end
  82. end
  83. private
  84. def client_id_gen
  85. SecureRandom.uuid
  86. end
  87. def client_id_verify
  88. return if !params[:client_id]
  89. sessions = Sessions.sessions
  90. return if sessions.exclude?(params[:client_id].to_s)
  91. params[:client_id].to_s
  92. end
  93. def log(data, client_id = '-')
  94. logger.info "client(#{client_id}) #{data}"
  95. end
  96. end