Chatwoot/app/services/notification/push_notification_service.rb

105 lines
3.2 KiB
Ruby

class Notification::PushNotificationService
include Rails.application.routes.url_helpers
pattr_initialize [:notification!]
def perform
return unless user_subscribed_to_notification?
notification_subscriptions.each do |subscription|
send_browser_push(subscription)
send_fcm_push(subscription)
send_push_via_chatwoot_hub(subscription)
end
end
private
delegate :user, to: :notification
delegate :notification_subscriptions, to: :user
delegate :notification_settings, to: :user
def user_subscribed_to_notification?
notification_setting = notification_settings.find_by(account_id: notification.account.id)
return true if notification_setting.public_send("push_#{notification.notification_type}?")
false
end
def conversation
@conversation ||= notification.conversation
end
def push_message
{
title: notification.push_message_title,
tag: "#{notification.notification_type}_#{conversation.display_id}_#{notification.id}",
url: push_url
}
end
def push_url
app_account_conversation_url(account_id: conversation.account_id, id: conversation.display_id)
end
def send_browser_push?(subscription)
VapidService.public_key && subscription.browser_push?
end
def send_browser_push(subscription)
return unless send_browser_push?(subscription)
Webpush.payload_send(
message: JSON.generate(push_message),
endpoint: subscription.subscription_attributes['endpoint'],
p256dh: subscription.subscription_attributes['p256dh'],
auth: subscription.subscription_attributes['auth'],
vapid: {
subject: push_url,
public_key: VapidService.public_key,
private_key: VapidService.private_key
},
ssl_timeout: 5,
open_timeout: 5,
read_timeout: 5
)
rescue Webpush::ExpiredSubscription
subscription.destroy!
rescue Errno::ECONNRESET, Net::OpenTimeout, Net::ReadTimeout => e
Rails.logger.error "Webpush operation error: #{e.message}"
end
def send_fcm_push(subscription)
return unless ENV['FCM_SERVER_KEY']
return unless subscription.fcm?
fcm = FCM.new(ENV.fetch('FCM_SERVER_KEY', nil))
response = fcm.send([subscription.subscription_attributes['push_token']], fcm_options)
remove_subscription_if_error(subscription, response)
end
def send_push_via_chatwoot_hub(subscription)
return if ENV['FCM_SERVER_KEY']
return unless ActiveModel::Type::Boolean.new.cast(ENV.fetch('ENABLE_PUSH_RELAY_SERVER', true))
return unless subscription.fcm?
ChatwootHub.send_browser_push([subscription.subscription_attributes['push_token']], fcm_options)
end
def remove_subscription_if_error(subscription, response)
subscription.destroy! if JSON.parse(response[:body])['results']&.first&.keys&.include?('error')
end
def fcm_options
{
notification: {
title: notification.notification_type.titleize,
body: notification.push_message_title,
sound: 'default'
},
android: { priority: 'high' },
data: { notification: notification.fcm_push_data.to_json },
collapse_key: "chatwoot_#{notification.primary_actor_type.downcase}_#{notification.primary_actor_id}"
}
end
end