link-stack/packages/zammad-addon-link/src/lib/cdr_signal_api.rb

157 lines
5.2 KiB
Ruby
Raw Normal View History

2026-02-10 08:36:04 +01:00
# frozen_string_literal: true
require 'json'
require 'net/http'
require 'net/https'
require 'uri'
# Direct Signal CLI API client for communicating with signal-cli-rest-api
# All Signal operations go through this single class
class CdrSignalApi
def initialize(base_url = nil)
@base_url = base_url || ENV.fetch('SIGNAL_CLI_URL', 'http://signal-cli-rest-api:8080')
end
# Fetch pending messages for a phone number
# GET /v1/receive/{number}
def fetch_messages(phone_number)
url = "#{@base_url}/v1/receive/#{CGI.escape(phone_number)}"
response = Faraday.get(url, nil, { 'Accept' => 'application/json' })
return [] unless response.success?
JSON.parse(response.body)
rescue JSON::ParserError, Faraday::Error => e
Rails.logger.error "CdrSignalApi: Failed to fetch messages for #{phone_number}: #{e.message}"
[]
end
# Fetch an attachment by ID
# GET /v1/attachments/{id}
def fetch_attachment(attachment_id)
url = "#{@base_url}/v1/attachments/#{CGI.escape(attachment_id)}"
response = Faraday.get(url)
return nil unless response.success?
response.body
rescue Faraday::Error => e
Rails.logger.error "CdrSignalApi: Failed to fetch attachment #{attachment_id}: #{e.message}"
nil
end
# List all groups for a phone number
# GET /v1/groups/{number}
def list_groups(phone_number)
url = "#{@base_url}/v1/groups/#{CGI.escape(phone_number)}"
response = Faraday.get(url, nil, { 'Accept' => 'application/json' })
return [] unless response.success?
JSON.parse(response.body)
rescue JSON::ParserError, Faraday::Error => e
Rails.logger.error "CdrSignalApi: Failed to list groups for #{phone_number}: #{e.message}"
[]
end
# Check if a phone number is registered with signal-cli
# GET /v1/about
def check_number(phone_number)
# Verify we can connect to signal-cli-rest-api
url = "#{@base_url}/v1/about"
response = Faraday.get(url, nil, { 'Accept' => 'application/json' })
return false unless response.success?
# Try to list groups for this number to verify it's registered
groups_url = "#{@base_url}/v1/groups/#{CGI.escape(phone_number)}"
groups_response = Faraday.get(groups_url, nil, { 'Accept' => 'application/json' })
groups_response.success?
rescue Faraday::Error => e
Rails.logger.error "CdrSignalApi: Failed to check number #{phone_number}: #{e.message}"
false
end
# Send a message via Signal CLI
# POST /v2/send
def send_message(from_number, recipients, message, options = {})
url = "#{@base_url}/v2/send"
data = {
number: from_number,
recipients: Array(recipients),
message: message
}
# Add base64 attachments if provided
if options[:attachments].present?
data[:base64Attachments] = options[:attachments].map { |a| a[:data] }
end
# Add quote parameters if provided
if options[:quote_timestamp] && options[:quote_author] && options[:quote_message]
data[:quoteTimestamp] = options[:quote_timestamp]
data[:quoteAuthor] = options[:quote_author]
data[:quoteMessage] = options[:quote_message]
end
response = Faraday.post(url, data.to_json, {
'Content-Type' => 'application/json',
'Accept' => 'application/json'
})
unless response.success?
Rails.logger.error "CdrSignalApi: Failed to send message: #{response.status} #{response.body}"
raise "Failed to send Signal message: #{response.status}"
end
JSON.parse(response.body)
rescue Faraday::Error => e
Rails.logger.error "CdrSignalApi: Failed to send message: #{e.message}"
raise "Failed to send Signal message: #{e.message}"
end
# Create a new Signal group
# POST /v1/groups/{number}
def create_group(phone_number, name:, members:, description: nil)
url = "#{@base_url}/v1/groups/#{CGI.escape(phone_number)}"
data = {
name: name,
members: Array(members),
description: description
}.compact
response = Faraday.post(url, data.to_json, {
'Content-Type' => 'application/json',
'Accept' => 'application/json'
})
unless response.success?
Rails.logger.error "CdrSignalApi: Failed to create group: #{response.status} #{response.body}"
raise "Failed to create Signal group: #{response.status}"
end
JSON.parse(response.body)
rescue Faraday::Error => e
Rails.logger.error "CdrSignalApi: Failed to create group: #{e.message}"
raise "Failed to create Signal group: #{e.message}"
end
# Update a Signal group
# PUT /v1/groups/{number}/{groupId}
def update_group(phone_number, group_id, name: nil, description: nil)
url = "#{@base_url}/v1/groups/#{CGI.escape(phone_number)}/#{CGI.escape(group_id)}"
data = {}
data[:name] = name if name.present?
data[:description] = description if description.present?
response = Faraday.put(url, data.to_json, {
'Content-Type' => 'application/json',
'Accept' => 'application/json'
})
response.success?
rescue Faraday::Error => e
Rails.logger.error "CdrSignalApi: Failed to update group: #{e.message}"
false
end
end