gitlab-org--gitlab-foss/app/channels/awareness_channel.rb

86 lines
2.3 KiB
Ruby

# frozen_string_literal: true
class AwarenessChannel < ApplicationCable::Channel # rubocop:disable Gitlab/NamespacedClass
REFRESH_INTERVAL = ENV.fetch("GITLAB_AWARENESS_REFRESH_INTERVAL_SEC", 60)
private_constant :REFRESH_INTERVAL
# Produces a refresh interval value, based of the
# GITLAB_AWARENESS_REFRESH_INTERVAL_SEC environment variable or the given
# default. Makes sure, that the interval after a jitter is applied, is never
# less than half the predefined interval.
def self.refresh_interval(range: -10..10)
min = REFRESH_INTERVAL / 2.to_f
[min.to_i, REFRESH_INTERVAL.to_i + rand(range)].max.seconds
end
private_class_method :refresh_interval
# keep clients updated about session membership
periodically every: self.refresh_interval do
transmit payload
end
def subscribed
reject unless valid_subscription?
return if subscription_rejected?
stream_for session, coder: ActiveSupport::JSON
session.join(current_user)
AwarenessChannel.broadcast_to(session, payload)
end
def unsubscribed
return if subscription_rejected?
session.leave(current_user)
AwarenessChannel.broadcast_to(session, payload)
end
# Allows a client to let the server know they are still around. This is not
# like a heartbeat mechanism. This can be triggered by any action that results
# in a meaningful "presence" update. Like scrolling the screen (debounce),
# window becoming active, user starting to type in a text field, etc.
def touch
session.touch!(current_user)
transmit payload
end
private
def valid_subscription?
current_user.present? && path.present?
end
def payload
{ collaborators: collaborators }
end
def collaborators
session.online_users_with_last_activity.map do |user, last_activity|
collaborator(user, last_activity)
end
end
def collaborator(user, last_activity)
{
id: user.id,
name: user.name,
username: user.username,
avatar_url: user.avatar_url(size: 36),
last_activity: last_activity,
last_activity_humanized: ActionController::Base.helpers.distance_of_time_in_words(
Time.zone.now, last_activity
)
}
end
def session
@session ||= AwarenessSession.for(path)
end
def path
params[:path]
end
end