require 'rack'
class MixpanelMiddleware
def initialize(app, mixpanel_token)
@app = app
@token = mixpanel_token
end
def call(env)
@env = env
@status, @headers, @response = @app.call(env)
update_response!
update_content_length!
delete_event_queue!
[@status, @headers, @response]
end
private
def update_response!
@response.each do |part|
if is_regular_request? && is_html_response?
part.gsub!("", "#{render_mixpanel_scripts}")
part.gsub!("", "#{render_event_tracking_scripts}")
elsif is_ajax_request? && is_html_response?
part.gsub!(part, render_event_tracking_scripts + part)
elsif is_ajax_request? && is_javascript_response?
part.gsub!(part, render_event_tracking_scripts(false) + part)
end
end
end
def update_content_length!
new_size = 0
@response.each{|part| new_size += part.bytesize}
@headers.merge!("Content-Length" => new_size.to_s)
end
def is_regular_request?
!is_ajax_request?
end
def is_ajax_request?
@env.has_key?("HTTP_X_REQUESTED_WITH") && @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest"
end
def is_html_response?
@headers["Content-Type"].include?("text/html") if @headers.has_key?("Content-Type")
end
def is_javascript_response?
@headers["Content-Type"].include?("text/javascript") if @headers.has_key?("Content-Type")
end
def render_mixpanel_scripts
<<-EOT
EOT
end
def delete_event_queue!
@env.delete('mixpanel_events')
end
def queue
return [] if !@env.has_key?('mixpanel_events') || @env['mixpanel_events'].empty?
@env['mixpanel_events']
end
def render_event_tracking_scripts(include_script_tag=true)
return "" if queue.empty?
output = queue.map {|event| %(mpmetrics.track("#{event[:event]}", #{event[:properties].to_json});) }.join("\n")
output = "try {#{output}} catch(err) {}"
include_script_tag ? "" : output
end
end