cartodb-4.42/lib/carto/named_maps/api.rb
2024-04-06 05:25:13 +00:00

199 lines
5.8 KiB
Ruby

require_relative 'template'
require_relative '../http/client'
require_dependency 'carto/named_maps/template'
module Carto
module NamedMaps
class Api
include ::LoggerHelper
HTTP_CONNECT_TIMEOUT_SECONDS = 45
HTTP_REQUEST_TIMEOUT_SECONDS = 60
RETRY_TIME_SECONDS = 2
MAX_RETRY_ATTEMPTS = 3
attr_accessor :user, :visualization
def initialize(visualization)
@visualization = visualization
@user = visualization.user
@named_map_template = Carto::NamedMaps::Template.new(visualization)
end
def index
stats_aggregator.timing('carto-named-maps-api.index') do
response = stats_aggregator.timing('call') do
http_client.get(url, request_params)
end
if response.code.to_s =~ /^2/
::JSON.parse(response.response_body).deep_symbolize_keys
else
log_response(response, 'index')
end
end
end
def create
stats_aggregator.timing('carto-named-maps-api.create') do
params = request_params
params[:body] = @named_map_template.to_json
response = http_client.post(url, params)
response_code = response.code
if response_code.to_s =~ /^2/
::JSON.parse(response.response_body).deep_symbolize_keys
elsif response_code != 409 # Ignore when max number of templates is reached
log_response(response, 'create')
end
end
end
def show
stats_aggregator.timing('carto-named-maps-api.show') do
response = stats_aggregator.timing('call') do
url = url(template_name: @named_map_template.name)
response = http_client.get(url, request_params)
end
response_code = response.code
if response_code.to_s =~ /^2/
::JSON.parse(response.response_body).deep_symbolize_keys
else
log_response(response, 'show') unless response_code == 404
end
end
end
def update(retries: 0)
stats_aggregator.timing('carto-named-maps-api.update') do
params = request_params
params[:body] = @named_map_template.to_json
response = http_client.put(url(template_name: @named_map_template.name), params)
response_code_string = response.code.to_s
if response_code_string =~ /^2/
::JSON.parse(response.response_body).deep_symbolize_keys
elsif response_code_string =~ /^5/ && retries < MAX_RETRY_ATTEMPTS
sleep(RETRY_TIME_SECONDS**retries)
update(retries: retries + 1)
else
log_response(response, 'update')
end
end
end
def destroy
stats_aggregator.timing('carto-named-maps-api.destroy') do
url = url(template_name: @named_map_template.name)
response = http_client.delete(url, request_params)
response_code = response.code
if response_code.to_s =~ /^2/
response.response_body
else
log_response(response, 'destroy') unless response_code == 404
end
end
end
def upsert
show ? update : create
end
private
def stats_aggregator
@@stats_aggregator_instance ||= CartoDB::Stats::EditorAPIs.instance
end
def url(template_name: '')
username = user.username
user_url = CartoDB.subdomainless_urls? ? "/user/#{username}" : ''
"#{protocol}://#{host(username)}:#{port}#{user_url}/api/v1/map/named/#{template_name}?api_key=#{user.api_key}"
end
def request_params
{
headers: headers(user.username),
ssl_verifypeer: ssl_verifypeer,
ssl_verifyhost: ssl_verifyhost,
followlocation: true,
connecttimeout: HTTP_CONNECT_TIMEOUT_SECONDS,
timeout: HTTP_REQUEST_TIMEOUT_SECONDS
}
end
def headers(username)
@headers ||= {
'content-type': 'application/json',
'host': domain(username)
}
end
def domain(username)
return @domain if @domain
config_domain = Cartodb.get_config(:tiler, 'internal', 'domain')
CartoDB.subdomainless_urls? ? config_domain : "#{username}.#{config_domain}"
end
def port
@port ||= Cartodb.get_config(:tiler, 'internal', 'port')
end
def protocol
@protocol ||= Cartodb.get_config(:tiler, 'internal', 'protocol')
end
def ssl_verifypeer
@verifycert ||= Cartodb.get_config(:tiler, 'internal', 'verifycert')
end
def ssl_verifyhost
ssl_verifypeer ? 2 : 0
end
def host(username)
return @host if @host
config_host = Cartodb.get_config(:tiler, 'internal', 'host')
@host ||= config_host.blank? ? domain(username) : config_host
end
def http_client
@http_client ||= Carto::Http::Client.get('named_maps')
end
def log_response(response, action)
log_error(
message: 'Error in named maps API',
current_user: user,
visualization_id: visualization.id,
action: action,
request_url: response.request.url,
status: response.code,
response_body: response.body
)
rescue Encoding::UndefinedConversionError => e
# Hotfix for preventing https://rollbar.com/carto/CartoDB/items/41457 until we find the root cause
# https://cartoteam.slack.com/archives/CEQLWTW9Z/p1599134417001900
# https://app.clubhouse.io/cartoteam/story/101908/fix-encoding-error-while-logging-request
Rollbar.error(e)
end
def log_context
super.merge(request_id: Carto::CurrentRequest.request_id, component: 'cartodb.named-maps-client')
end
end
end
end