Files
bit/app/services/click_tracker.cr
T
2025-03-18 11:07:34 +01:00

55 lines
1.7 KiB
Crystal

require "user_agent_parser"
UserAgent.load_regexes(File.read("data/uap_core_regexes.yaml"))
IpLookup.load_mmdb("data/GeoLite2-Country.mmdb")
module App::Services
class ClickTracker
@@queue = Channel(Tuple(String, String, String, String, String)).new(1000)
@@initialized = false
def self.init
return if @@initialized
@@initialized = true
# Single worker fiber to process the queue
spawn do
Log.info { "ClickTracker worker started" }
loop do
begin
link_id, client_ip, user_agent_str, source, referer = @@queue.receive
ip_lookup = client_ip != "Unknown" ? IpLookup.new(client_ip) : nil
country = ip_lookup.try &.country.try &.code
user_agent = user_agent_str != "Unknown" ? UserAgent.new(user_agent_str) : nil
click = App::Models::Click.new
click.id = UUID.v4.to_s
click.link_id = link_id
click.country = country
click.user_agent = user_agent_str
click.browser = user_agent.try &.family
click.os = user_agent.try &.os.try &.family
click.referer = referer
changeset = App::Lib::Database.insert(click)
if changeset.errors.any?
Log.error { "Logging click event failed: #{changeset.errors}" }
end
rescue ex
Log.error { "Error processing click: #{ex.message}" }
sleep 0.1.seconds
end
end
end
end
def self.track(link_id : String, client_ip : String, user_agent : String, source : String, referer : String)
init if !@@initialized
@@queue.send({link_id, client_ip, user_agent, source, referer})
end
end
end