completed SMS gateway project

This commit is contained in:
Min Zeya Phyo
2025-10-22 17:22:17 +08:00
commit c883fa7128
190 changed files with 16294 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end

View File

@@ -0,0 +1,31 @@
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_gateway
def connect
self.current_gateway = find_verified_gateway
logger.info "Gateway #{current_gateway.device_id} connected"
end
private
def find_verified_gateway
# Get API key from request params
api_key = request.params[:api_key]
if api_key.blank?
reject_unauthorized_connection
end
# Hash the API key and find gateway
api_key_digest = Digest::SHA256.hexdigest(api_key)
gateway = Gateway.find_by(api_key_digest: api_key_digest, active: true)
if gateway
gateway
else
reject_unauthorized_connection
end
end
end
end

View File

@@ -0,0 +1,99 @@
class GatewayChannel < ApplicationCable::Channel
def subscribed
# Gateway is already authenticated at the connection level
# current_gateway is set by ApplicationCable::Connection
@gateway = current_gateway
unless @gateway
reject
return
end
# Subscribe to gateway-specific channel
stream_for @gateway
# Update gateway status
@gateway.heartbeat!
Rails.logger.info("Gateway #{@gateway.device_id} subscribed to GatewayChannel")
end
def unsubscribed
# Update gateway status when disconnected
if @gateway
@gateway.mark_offline!
Rails.logger.info("Gateway #{@gateway.device_id} disconnected from WebSocket")
end
end
def receive(data)
return unless @gateway
# Handle incoming messages from gateway
case data["action"]
when "heartbeat"
handle_heartbeat(data)
when "delivery_report"
handle_delivery_report(data)
when "message_received"
handle_message_received(data)
else
Rails.logger.warn("Unknown action received: #{data['action']}")
end
rescue StandardError => e
Rails.logger.error("Error processing gateway message: #{e.message}")
end
private
def handle_heartbeat(data)
@gateway.heartbeat!
# Update metadata if provided
metadata = {
battery_level: data["battery_level"],
signal_strength: data["signal_strength"],
messages_in_queue: data["messages_in_queue"]
}.compact
@gateway.update(metadata: metadata) if metadata.any?
end
def handle_delivery_report(data)
message_id = data["message_id"]
status = data["status"]
error_message = data["error_message"]
sms = SmsMessage.find_by(message_id: message_id)
return unless sms
case status
when "delivered"
sms.mark_delivered!
when "failed"
sms.mark_failed!(error_message)
RetryFailedSmsJob.perform_later(sms.id) if sms.can_retry?
end
end
def handle_message_received(data)
sender = data["sender"]
message = data["message"]
timestamp = data["timestamp"] || Time.current
# Create inbound SMS
sms = SmsMessage.create!(
gateway: @gateway,
direction: "inbound",
phone_number: sender,
message_body: message,
status: "delivered",
delivered_at: timestamp
)
@gateway.increment_received_count!
# Process inbound message
ProcessInboundSmsJob.perform_later(sms.id)
end
end