You're breathtaking!
This commit is contained in:
26
Source/ThirdParty/UniversalAnalytics/UniversalAnalytics.Build.cs
vendored
Normal file
26
Source/ThirdParty/UniversalAnalytics/UniversalAnalytics.Build.cs
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using Flax.Build;
|
||||
using Flax.Build.NativeCpp;
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/adswerve/universal-analytics-c
|
||||
/// </summary>
|
||||
public class UniversalAnalytics : ThirdPartyModule
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.BSD3Clause;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Setup(BuildOptions options)
|
||||
{
|
||||
base.Setup(options);
|
||||
|
||||
options.PrivateDependencies.Add("curl");
|
||||
}
|
||||
}
|
||||
119
Source/ThirdParty/UniversalAnalytics/http.cpp
vendored
Normal file
119
Source/ThirdParty/UniversalAnalytics/http.cpp
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
/******************************************************************************
|
||||
* Universal Analytics for C
|
||||
* Copyright (c) 2013, Analytics Pros
|
||||
*
|
||||
* This project is free software, distributed under the BSD license.
|
||||
* Analytics Pros offers consulting and integration services if your firm needs
|
||||
* assistance in strategy, implementation, or auditing existing work.
|
||||
******************************************************************************/
|
||||
|
||||
#include "http.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/* This module provides an abstraction over CURL's HTTP methods,
|
||||
* in hope of decoupling HTTP processing from the rest of our tracking
|
||||
* logic, possibly supporting alternative HTTP libraries in the future.
|
||||
*/
|
||||
|
||||
|
||||
/* Data handler for CURL to silence it's default output */
|
||||
size_t curl_null_data_handler(char *ptr, size_t size, size_t nmemb, void *userdata){
|
||||
#if UA_DEBUG
|
||||
printf("Processing response 0x%lx\n", (unsigned long int) userdata);
|
||||
#endif
|
||||
return (nmemb * size);
|
||||
}
|
||||
|
||||
static inline unsigned int _minimum(unsigned int a, unsigned int b){
|
||||
return (b < a) ? b : a;
|
||||
}
|
||||
|
||||
|
||||
/* Sequentially de-queue requests */
|
||||
int curl_multi_unload(CURLM* handler, CURL* requests[], unsigned int total){
|
||||
int count = _minimum(UA_MAX_QUERY_QUEUE, total);
|
||||
int i = count;
|
||||
|
||||
#if UA_DEBUG
|
||||
printf("Processing %d requests...\n", count);
|
||||
#endif
|
||||
|
||||
while(count){
|
||||
curl_multi_perform(handler, & count);
|
||||
}
|
||||
|
||||
while(i--){
|
||||
curl_easy_cleanup(requests[ i ]);
|
||||
requests[ i ] = NULL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Unload the queue and free any related memory
|
||||
* - Process queued requests
|
||||
* - Trigger CURL's native cleanup (free()) on its resources
|
||||
*/
|
||||
void HTTPcleanup(HTTPQueue_t* queue){
|
||||
if(NULL != queue->handler){
|
||||
curl_multi_unload(queue->handler, queue->requests, queue->count);
|
||||
curl_multi_cleanup(queue->handler);
|
||||
queue->handler = NULL;
|
||||
}
|
||||
queue->count = 0;
|
||||
}
|
||||
|
||||
/* Prepare the CURL Multi handler */
|
||||
void HTTPsetup(HTTPQueue_t* queue){
|
||||
queue->count = 0;
|
||||
queue->handler = curl_multi_init();
|
||||
curl_multi_setopt(queue->handler, CURLMOPT_PIPELINING, 1);
|
||||
}
|
||||
|
||||
/* Process queued requests (but don't reset) */
|
||||
void HTTPflush(HTTPQueue_t* queue){
|
||||
assert(NULL != queue->handler);
|
||||
if(0 < queue->count){
|
||||
curl_multi_unload(queue->handler, queue->requests, queue->count);
|
||||
}
|
||||
queue->count = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Enqueue a POST using CURL */
|
||||
int HTTPenqueue(HTTPQueue_t* queue, const char* endpoint, const char* useragent, const char* query, unsigned int query_len){
|
||||
|
||||
assert(NULL != queue);
|
||||
assert(NULL != query);
|
||||
assert(NULL != endpoint);
|
||||
assert(NULL != useragent);
|
||||
|
||||
CURLM* handler = queue->handler;
|
||||
CURL* curl = curl_easy_init();
|
||||
|
||||
#if UA_DEBUG
|
||||
printf("Queueing: \n\t- %s\n\t- %s\n\t- %s\n", endpoint, useragent, query);
|
||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
|
||||
unsigned int queue_capacity = (UA_MAX_QUERY_QUEUE - queue->count);
|
||||
|
||||
if(queue_capacity == 0){
|
||||
HTTPflush(queue); // Process queued requests if no space remains
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, endpoint);
|
||||
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, query);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, useragent);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_null_data_handler);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl);
|
||||
|
||||
curl_multi_add_handle(handler, curl);
|
||||
|
||||
queue->requests[ queue->count++ % UA_MAX_QUERY_QUEUE ] = curl;
|
||||
|
||||
return queue->count;
|
||||
}
|
||||
|
||||
|
||||
52
Source/ThirdParty/UniversalAnalytics/http.h
vendored
Normal file
52
Source/ThirdParty/UniversalAnalytics/http.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/******************************************************************************
|
||||
* Universal Analytics for C
|
||||
* Copyright (c) 2013, Analytics Pros
|
||||
*
|
||||
* This project is free software, distributed under the BSD license.
|
||||
* Analytics Pros offers consulting and integration services if your firm needs
|
||||
* assistance in strategy, implementation, or auditing existing work.
|
||||
******************************************************************************/
|
||||
|
||||
/* This module provides an abstraction over CURL for HTTP handling.
|
||||
* Currently we rely on CURL to process HTTP requests to Google's servers,
|
||||
* however its dependencies may not be practical to support in some systems,
|
||||
* so this abstraction will hopefully make it simpler to support alternative
|
||||
* HTTP libraries in the future. */
|
||||
|
||||
/* Header guard, prevent multiple definition */
|
||||
#ifndef HTTP_H
|
||||
#define HTTP_H 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#define UA_MAX_QUERY_LEN 4096
|
||||
#define UA_MAX_QUERY_QUEUE 10
|
||||
|
||||
#define UA_DEBUG 0
|
||||
|
||||
/* Callback types */
|
||||
typedef void* (*UAGenericCallback)(void*);
|
||||
typedef int (*UAEventCallback)(char*, void*);
|
||||
typedef int (*UAHTTPPOSTProcessor)(char*, char*, char*);
|
||||
typedef char* (*UAURLEncoder)(char*);
|
||||
|
||||
|
||||
|
||||
typedef struct HTTPQueue_t {
|
||||
|
||||
unsigned int count;
|
||||
CURLM* handler;
|
||||
CURL* requests[ UA_MAX_QUERY_QUEUE ];
|
||||
|
||||
} HTTPQueue_t;
|
||||
|
||||
|
||||
void HTTPcleanup(HTTPQueue_t* queue);
|
||||
void HTTPsetup(HTTPQueue_t* queue);
|
||||
void HTTPflush(HTTPQueue_t* queue);
|
||||
|
||||
|
||||
int HTTPenqueue(HTTPQueue_t* queue, const char* endpoint, const char* useragent, const char* query, unsigned int query_len);
|
||||
|
||||
#endif /* HTTP_H */
|
||||
178
Source/ThirdParty/UniversalAnalytics/string/encode.cpp
vendored
Normal file
178
Source/ThirdParty/UniversalAnalytics/string/encode.cpp
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
/******************************************************************************
|
||||
* Universal Analytics for C
|
||||
* -- URL encoding module for UTF-8 compatibility with Google Analytics
|
||||
* Copyright (c) 2013, Analytics Pros
|
||||
*
|
||||
* This project is free software, distributed under the BSD license.
|
||||
* Analytics Pros offers consulting and integration services if your firm needs
|
||||
* assistance in strategy, implementation, or auditing existing work.
|
||||
******************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#include "encode.h"
|
||||
|
||||
/* The following constants are symbolized for readability in later encoding phases */
|
||||
#define ASCII_HIGH 0x7F
|
||||
#define UTF8_INVALID 0xFFFF
|
||||
#define UTF8_SWAPCHAR 0xFFFE
|
||||
#define UTF8_HIGH_TWO_BYTES 0x7FF
|
||||
#define UTF8_HIGH_THREE_BYTES 0xFFFD
|
||||
#define UTF8_HIGH_FOUR_BYTES 0x1FFFFF
|
||||
#define UTF8_HIGH_FIVE_BYTES 0x3FFFFFF
|
||||
#define UTF8_HIGH_SIX_BYTES 0x7FFFFFFF
|
||||
|
||||
|
||||
#define _minimum(a, b) ((a < b) ? a : b)
|
||||
|
||||
|
||||
/* Mapping for hexadecimal conversion */
|
||||
static const char _hexchar[] = "0123456789abcdef";
|
||||
|
||||
|
||||
// Write a hexidecimal value (32 bit) to a character buffer
|
||||
unsigned int hexadecimal(char* output, unsigned int value){
|
||||
|
||||
assert(NULL != output);
|
||||
|
||||
__uint a = (value >> 28) & 0xF;
|
||||
__uint b = (value >> 24) & 0xF;
|
||||
__uint c = (value >> 20) & 0xF;
|
||||
__uint d = (value >> 16) & 0xF;
|
||||
__uint e = (value >> 12) & 0xF;
|
||||
__uint f = (value >> 8) & 0xF;
|
||||
__uint g = (value >> 4) & 0xF;
|
||||
__uint h = (value & 0xF);
|
||||
|
||||
__uint i = 0;
|
||||
|
||||
if(a) output[i++] = _hexchar[ (int) a ];
|
||||
if(b || a) output[i++] = _hexchar[ (int) b ];
|
||||
if(c || b || a) output[i++] = _hexchar[ (int) c ];
|
||||
if(d || c || b || a) output[i++] = _hexchar[ (int) d ];
|
||||
if(e || d || c || b || a) output[i++] = _hexchar[ (int) e ];
|
||||
if(f || e || d || c || b || a) output[i++] = _hexchar[ (int) f ];
|
||||
if(g || f || e || d || c || b || a) output[i++] = _hexchar[ (int) g ];
|
||||
output[i++] = _hexchar[ (int) h ];
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
// Primarily intended to aid the translation of binary MD5 digests
|
||||
unsigned int hexdigest(char* hex_output, unsigned char* binary, unsigned int binary_len){
|
||||
unsigned int i;
|
||||
unsigned int o = 0;
|
||||
for(i = 0; i < binary_len; i++){
|
||||
o += hexadecimal(hex_output + o, (unsigned int) binary[i]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int isASCIIcompat_char(char char_val){
|
||||
return (char_val == 0x09 || char_val == 0x0A || char_val == 0x0D || (0x20 <= char_val && char_val <= 0x7F));
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t urlencode_put(char* result, size_t result_max, const char *multibyte_input, size_t input_len){
|
||||
|
||||
assert(NULL != result);
|
||||
assert(NULL != multibyte_input);
|
||||
|
||||
unsigned int i = 0;
|
||||
unsigned int r = 0;
|
||||
unsigned int offset = 0;
|
||||
wchar_t current;
|
||||
|
||||
mbtowc(NULL, NULL, 0); // Reset multibyte state
|
||||
|
||||
do {
|
||||
// Convert the current multi-byte character into a wide representation (i.e. unsigned long int)
|
||||
offset += mbtowc(& current, (multibyte_input) + (offset), MB_CUR_MAX);
|
||||
|
||||
if(current == 0){
|
||||
break; // Stop on NULL termination
|
||||
}
|
||||
|
||||
// Spaces are encoded as "plus" (+)
|
||||
else if(current == ' ' && r < result_max){
|
||||
result[r++] = '+';
|
||||
continue;
|
||||
}
|
||||
|
||||
// These characters are allowed as literals
|
||||
else if((iswalnum(current) || current == '-' || current == '.' || current == '~') && r < result_max){
|
||||
result[r++] = (char)current;
|
||||
}
|
||||
|
||||
// Standard ASCII characters are encoded simply
|
||||
else if(isASCIIcompat_char((char)current) && r < result_max){
|
||||
result[r++] = '%';
|
||||
r += hexadecimal(result + r, (unsigned int) (current & 0xFF));
|
||||
}
|
||||
|
||||
// The method |mbtowc| (above) takes care of splitting UTF8 bytes,
|
||||
// so this can run directly...
|
||||
else if(current >= ASCII_HIGH && current <= UTF8_HIGH_SIX_BYTES && (r +2) < result_max){
|
||||
result[r++] = '%';
|
||||
r+= hexadecimal(result + r, (unsigned int) current);
|
||||
}
|
||||
|
||||
|
||||
// This would seem to be an encoding error.
|
||||
// Considering fall-back to "hexdigest" representation.
|
||||
else if(result_max > r) {
|
||||
result[r++] = '*';
|
||||
break;
|
||||
}
|
||||
|
||||
} while((i++) < input_len && (r < result_max));
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
size_t urlencode_put_limit(const char* mb_input, char* output, size_t output_limit){
|
||||
assert(NULL != mb_input);
|
||||
assert(NULL != output);
|
||||
|
||||
size_t input_len = mbstowcs(NULL, mb_input, 0) +1;
|
||||
memset(output, 0, output_limit);
|
||||
|
||||
return urlencode_put(output, output_limit, mb_input, input_len);
|
||||
}
|
||||
|
||||
/* Create a new character buffer, and write the given input as URL-encoded (UTF-8) */
|
||||
char* urlencode(const char* mb_input){
|
||||
assert(NULL != mb_input);
|
||||
|
||||
size_t input_len = mbstowcs(NULL, mb_input, 0) +1;
|
||||
|
||||
// Prepare the output buffer; in some cases each character input could result
|
||||
// in 12 characters encoded output ['%' + XX (hex), for up to 4 bytes]
|
||||
unsigned long int output_allocation = sizeof(char) * ((unsigned long int)input_len * 12);
|
||||
char* output = (char*)malloc(output_allocation);
|
||||
memset(output, 0, output_allocation);
|
||||
|
||||
urlencode_put(output, output_allocation, mb_input, input_len);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/* For compatibility with our former encoding model... */
|
||||
unsigned int encodeURIComponent(char input[], char output[], const unsigned int input_len, const unsigned int output_max){
|
||||
return (unsigned int)urlencode_put(output, output_max, input, input_len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
28
Source/ThirdParty/UniversalAnalytics/string/encode.h
vendored
Normal file
28
Source/ThirdParty/UniversalAnalytics/string/encode.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/******************************************************************************
|
||||
* Universal Analytics for C
|
||||
* -- URL encoding module for UTF-8 compatibility with Google Analytics
|
||||
* Copyright (c) 2013, Analytics Pros
|
||||
*
|
||||
* This project is free software, distributed under the BSD license.
|
||||
* Analytics Pros offers consulting and integration services if your firm needs
|
||||
* assistance in strategy, implementation, or auditing existing work.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#ifndef UA_ENCODE_H
|
||||
#define UA_ENCODE_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
typedef unsigned int __uint;
|
||||
|
||||
char* urlencode(const char* input);
|
||||
size_t urlencode_put(char* result, size_t result_max, const char *mb_input, size_t input_len);
|
||||
|
||||
// For compatibility..
|
||||
unsigned int encodeURIComponent(char input[], char output[], const unsigned int input_len, const unsigned int output_max);
|
||||
|
||||
unsigned int hexdigest(char* hex_output, unsigned char* md5_binary, unsigned int binary_len);
|
||||
|
||||
|
||||
#endif /* UA_ENCODE_H */
|
||||
413
Source/ThirdParty/UniversalAnalytics/universal-analytics.cpp
vendored
Normal file
413
Source/ThirdParty/UniversalAnalytics/universal-analytics.cpp
vendored
Normal file
@@ -0,0 +1,413 @@
|
||||
/******************************************************************************
|
||||
* Universal Analytics for C
|
||||
* Copyright (c) 2013, Analytics Pros
|
||||
*
|
||||
* This project is free software, distributed under the BSD license.
|
||||
* Analytics Pros offers consulting and integration services if your firm needs
|
||||
* assistance in strategy, implementation, or auditing existing work.
|
||||
******************************************************************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "universal-analytics.h"
|
||||
|
||||
#define UA_MEM_MAGIC_UNSET 0xDEADC0DE
|
||||
#define UA_MEM_MAGIC_CONFIG 0xADDED00
|
||||
#define UA_DEFAULT_OPTION_QUEUE 1
|
||||
|
||||
static const char UA_ENDPOINT[] = "https://www.google-analytics.com/collect";
|
||||
static const char UA_USER_AGENT_DEFAULT[] = "Analytics Pros - Universal Analytics for C";
|
||||
static const char UA_PROTOCOL_VERSION[] = "1";
|
||||
|
||||
|
||||
|
||||
/* Define tracking type strings; these are protocol-constants for
|
||||
* Measurement Protocol v1. We may eventually migrate these to a separate
|
||||
* protocol module. */
|
||||
static inline int populateTypeNames(char* types[]){
|
||||
types[UA_PAGEVIEW] = "pageview";
|
||||
types[UA_APPVIEW] = "screenview";
|
||||
types[UA_SCREENVIEW] = "screenview";
|
||||
types[UA_EVENT] = "event";
|
||||
types[UA_TRANSACTION] = "trans";
|
||||
types[UA_TRANSACTION_ITEM] = "item";
|
||||
types[UA_TIMING] = "timing";
|
||||
types[UA_SOCIAL] = "social";
|
||||
types[UA_EXCEPTION] = "exception";
|
||||
return UA_MAX_TYPES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* List of parameter names (strings) corresponding to our field indexes;
|
||||
* these are also protocol-constants for Measurement Protocol v1.
|
||||
* We may eventually migrate these to a separate protocol module. */
|
||||
static inline void populateParameterNames(char* params[], const char* custom_params){
|
||||
int i, j;
|
||||
char* cur;
|
||||
params[UA_TRACKING_ID] = "tid";
|
||||
params[UA_CLIENT_ID] = "cid";
|
||||
params[UA_USER_ID] = "uid";
|
||||
params[UA_ANONYMIZE_IP] = "aip";
|
||||
params[UA_TRACKING_TYPE] = "t";
|
||||
params[UA_DOCUMENT_PATH] = "dp";
|
||||
params[UA_DOCUMENT_TITLE] = "dt";
|
||||
params[UA_DOCUMENT_LOCATION] = "dl";
|
||||
params[UA_DOCUMENT_HOSTNAME] = "dh";
|
||||
params[UA_DOCUMENT_REFERRER] = "dr";
|
||||
params[UA_DOCUMENT_ENCODING] = "de";
|
||||
params[UA_QUEUE_TIME_MS] = "qt";
|
||||
params[UA_CACHE_BUSTER] = "z";
|
||||
params[UA_SESSION_CONTROL] = "sc";
|
||||
params[UA_CAMPAIGN_NAME] = "cn";
|
||||
params[UA_CAMPAIGN_SOURCE] = "cs";
|
||||
params[UA_CAMPAIGN_MEDIUM] = "cm";
|
||||
params[UA_CAMPAIGN_KEYWORD] = "ck";
|
||||
params[UA_CAMPAIGN_CONTENT] = "cc";
|
||||
params[UA_CAMPAIGN_ID] = "ci";
|
||||
params[UA_SCREEN_RESOLUTION] = "sr";
|
||||
params[UA_VIEWPORT_SIZE] = "vp";
|
||||
params[UA_SCREEN_COLORS] = "sd";
|
||||
params[UA_USER_LANGUAGE] = "ul";
|
||||
params[UA_USER_AGENT] = "ua";
|
||||
params[UA_APP_NAME] = "an";
|
||||
params[UA_APP_ID] = "aid";
|
||||
params[UA_APP_VERSION] = "av";
|
||||
params[UA_APP_INSTALLER_ID] = "aiid";
|
||||
params[UA_CONTENT_DESCRIPTION] = "cd";
|
||||
params[UA_SCREEN_NAME] = "cd";
|
||||
params[UA_EVENT_CATEGORY] = "ec";
|
||||
params[UA_EVENT_ACTION] = "ea";
|
||||
params[UA_EVENT_LABEL] = "el";
|
||||
params[UA_EVENT_VALUE] = "ev";
|
||||
params[UA_NON_INTERACTIVE] = "ni";
|
||||
params[UA_SOCIAL_ACTION] = "sa";
|
||||
params[UA_SOCIAL_NETWORK] = "sn";
|
||||
params[UA_SOCIAL_TARGET] = "st";
|
||||
params[UA_EXCEPTION_DESCRIPTION] = "exd";
|
||||
params[UA_EXCEPTION_FATAL] = "exf";
|
||||
params[UA_TRANSACTION_ID] = "ti";
|
||||
params[UA_TRANSACTION_AFFILIATION] = "ta";
|
||||
params[UA_TRANSACTION_REVENUE] = "tr";
|
||||
params[UA_TRANSACTION_SHIPPING] = "ts";
|
||||
params[UA_TRANSACTION_TAX] = "tt";
|
||||
params[UA_TRANSACTION_CURRENCY] = "cu";
|
||||
params[UA_CURRENCY_CODE] = "cu"; /* for compatibility with Google's naming convention */
|
||||
params[UA_ITEM_CODE] = "ic" ;
|
||||
params[UA_ITEM_NAME] = "in";
|
||||
params[UA_ITEM_VARIATION] = "iv"; /* a more literal acronym/alias */
|
||||
params[UA_ITEM_CATEGORY] = "iv"; /* for compatibility with Google's naming convention */
|
||||
params[UA_ITEM_PRICE] = "ip";
|
||||
params[UA_ITEM_QUANTITY] = "iq";
|
||||
params[UA_TIMING_CATEGORY] = "utc";
|
||||
params[UA_TIMING_VARIABLE] = "utv";
|
||||
params[UA_TIMING_LABEL] = "utl";
|
||||
params[UA_TIMING_TIME] = "utt";
|
||||
params[UA_TIMING_DNS] = "dns";
|
||||
params[UA_TIMING_PAGE_LOAD] = "pdt";
|
||||
params[UA_TIMING_REDIRECT] = "rrt";
|
||||
params[UA_TIMING_TCP_CONNECT] = "tcp";
|
||||
params[UA_TIMING_SERVER_RESPONSE] = "srt";
|
||||
params[UA_VERSION_NUMBER] = "v";
|
||||
params[UA_ADWORDS_ID] = "gclid";
|
||||
params[UA_DISPLAY_AD_ID] = "dclid";
|
||||
params[UA_LINK_ID] = "linkid";
|
||||
params[UA_JAVA_ENABLED] = "je";
|
||||
params[UA_FLASH_VERSION] = "fl";
|
||||
|
||||
/* Populate dimension space */
|
||||
for(i = 0; i < UA_MAX_CUSTOM_DIMENSION; i++){
|
||||
cur = (char*) (custom_params + (i * UA_CUSTOM_PARAM_LEN));
|
||||
sprintf(cur, "cd%d", i + 1);
|
||||
params[ i + UA_START_CDIMENSIONS ] = cur; /* link parameter name */
|
||||
}
|
||||
|
||||
/* Populate metric space */
|
||||
for(j = 0; j < UA_MAX_CUSTOM_METRIC; j++){
|
||||
cur = (char*) (custom_params + ((i + j) * UA_CUSTOM_PARAM_LEN));
|
||||
sprintf(cur, "cm%d", j + 1);
|
||||
params[ j + UA_START_CMETRICS ] = cur; /* link parameter name */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Retrieve a field name (pointer) by its ID
|
||||
* (and appropriate offset for custom parameters */
|
||||
static inline char* getOptionName(char* field_names[], trackingField_t field, unsigned int slot_id){
|
||||
switch(field){
|
||||
case UA_CUSTOM_METRIC:
|
||||
return field_names[ UA_START_CMETRICS + slot_id - 1 ];
|
||||
case UA_CUSTOM_DIMENSION:
|
||||
return field_names[ UA_START_CDIMENSIONS + slot_id - 1 ];
|
||||
default:
|
||||
return field_names[ field ];
|
||||
}
|
||||
}
|
||||
|
||||
static inline int getFieldPosition(trackingField_t field, unsigned int slot_id){
|
||||
switch(field){
|
||||
case UA_CUSTOM_METRIC:
|
||||
return UA_START_CMETRICS + slot_id - 1;
|
||||
case UA_CUSTOM_DIMENSION:
|
||||
return UA_START_CDIMENSIONS + slot_id - 1;
|
||||
default:
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Retrieve the tracking-type parameter name (pointer) */
|
||||
static inline char* getTrackingType(UATracker_t* tracker, trackingType_t type){
|
||||
assert(NULL != tracker);
|
||||
assert((*tracker).__configured__ == UA_MEM_MAGIC_CONFIG);
|
||||
|
||||
return tracker->map_types[ type ];
|
||||
}
|
||||
|
||||
/* Void all memory allocated to tracking parameters (pointers) */
|
||||
static inline void initParameterState(UAParameter_t params[], unsigned int howmany){
|
||||
memset(params, 0, howmany * (sizeof(UAParameter_t)));
|
||||
}
|
||||
|
||||
/* Void a tracker's memory */
|
||||
void cleanTracker(UATracker_t* tracker){
|
||||
assert(NULL != tracker);
|
||||
if((*tracker).__configured__ == UA_MEM_MAGIC_CONFIG){
|
||||
HTTPcleanup(& tracker->queue); // run any queued requests...
|
||||
}
|
||||
memset(tracker, 0, sizeof(UATracker_t));
|
||||
}
|
||||
|
||||
|
||||
/* Clean out ephemeral state & query cache */
|
||||
static inline void resetQuery(UATracker_t* tracker){
|
||||
initParameterState(tracker->ephemeral_parameters, UA_MAX_PARAMETERS);
|
||||
memset(tracker->query, 0, UA_MAX_QUERY_LEN);
|
||||
tracker->query_len = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Define a single parameter's name/value/slot */
|
||||
static inline void setParameterCore(char* field_names[], UAParameter_t params[], trackingField_t field, unsigned int slot_id, const char* value){
|
||||
int position = getFieldPosition(field, slot_id);
|
||||
char* name = getOptionName(field_names, field, slot_id);
|
||||
assert(NULL != name);
|
||||
params[ position ].field = field;
|
||||
params[ position ].name = name;
|
||||
params[ position ].value = (char*) value;
|
||||
params[ position ].slot_id = slot_id;
|
||||
}
|
||||
|
||||
/* Populate several parameters (pointers) given a set of options */
|
||||
static inline void setParameterList(char* field_names[], UAParameter_t params[], UAOptionNode_t options[], unsigned int howmany){
|
||||
unsigned int i;
|
||||
for(i = 0; i < howmany; i++){
|
||||
if(options[i].field < 1){
|
||||
/* Only populate legitimate fields... skip the bad ones (or NULL) */
|
||||
continue;
|
||||
}
|
||||
setParameterCore(field_names, params, options[i].field, options[i].slot_id, options[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Populate several lifetime/permanent or temporary/ephemeral values based on scope */
|
||||
static inline void setParameterStateList(UATracker_t* tracker, stateScopeFlag_t flag, UAOptionNode_t options[]){
|
||||
assert(NULL != tracker);
|
||||
assert((*tracker).__configured__ == UA_MEM_MAGIC_CONFIG);
|
||||
switch(flag){
|
||||
case UA_PERMANENT:
|
||||
setParameterList(tracker->map_parameters, tracker->lifetime_parameters, options, UA_MAX_PARAMETERS);
|
||||
break;
|
||||
case UA_EPHEMERAL:
|
||||
setParameterList(tracker->map_parameters, tracker->ephemeral_parameters, options, UA_MAX_PARAMETERS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Populate a single lifetime/permanent or temporary/ephemeral value based on scope */
|
||||
static inline void setParameterState(UATracker_t* tracker, stateScopeFlag_t flag, trackingField_t field, unsigned int slot_id, char* value ){
|
||||
assert(NULL != tracker);
|
||||
assert((*tracker).__configured__ == UA_MEM_MAGIC_CONFIG);
|
||||
switch(flag){
|
||||
case UA_PERMANENT:
|
||||
setParameterCore(tracker->map_parameters, tracker->lifetime_parameters, field, slot_id, value);
|
||||
break;
|
||||
case UA_EPHEMERAL:
|
||||
setParameterCore(tracker->map_parameters, tracker->ephemeral_parameters, field, slot_id, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setTrackerOption(UATracker_t* tracker, UATrackerOption_t option, int value){
|
||||
assert(NULL != tracker);
|
||||
assert(UA_MAX_TRACKER_OPTION > (int) option);
|
||||
assert(0 <= option);
|
||||
tracker->options[ option ] = value;
|
||||
}
|
||||
|
||||
int getTrackerOption(UATracker_t* tracker, UATrackerOption_t option){
|
||||
assert(NULL != tracker);
|
||||
return tracker->options[ option ];
|
||||
}
|
||||
|
||||
|
||||
/* Set up an already-allocated tracker
|
||||
* - Clear out the whole tracker space
|
||||
* - Populate parameter names
|
||||
* - Define lifetime tracker values
|
||||
*/
|
||||
void initTracker(UATracker_t* tracker, char* trackingId, char* clientId, char* userId){
|
||||
assert(NULL != tracker);
|
||||
cleanTracker(tracker);
|
||||
|
||||
(*tracker).__configured__ = UA_MEM_MAGIC_CONFIG;
|
||||
|
||||
tracker->user_agent = (char*) UA_USER_AGENT_DEFAULT;
|
||||
|
||||
populateTypeNames(tracker->map_types);
|
||||
populateParameterNames(tracker->map_parameters, tracker->map_custom);
|
||||
|
||||
memset(& tracker->query, 0, UA_MAX_QUERY_LEN);
|
||||
|
||||
HTTPsetup(& tracker->queue);
|
||||
|
||||
|
||||
setParameterCore(tracker->map_parameters, tracker->lifetime_parameters, UA_VERSION_NUMBER, 0, UA_PROTOCOL_VERSION);
|
||||
setParameterCore(tracker->map_parameters, tracker->lifetime_parameters, UA_TRACKING_ID, 0, trackingId);
|
||||
setParameterCore(tracker->map_parameters, tracker->lifetime_parameters, UA_CLIENT_ID, 0, clientId);
|
||||
setParameterCore(tracker->map_parameters, tracker->lifetime_parameters, UA_USER_ID, 0, userId);
|
||||
|
||||
setTrackerOption(tracker, UA_OPTION_QUEUE, UA_DEFAULT_OPTION_QUEUE);
|
||||
|
||||
}
|
||||
|
||||
/* Allocate space for a tracker & initialize it */
|
||||
UATracker_t* createTracker(char* trackingId, char* clientId, char* userId){
|
||||
UATracker_t* new_tracker = (UATracker_t*)malloc(sizeof(UATracker_t));
|
||||
initTracker(new_tracker, trackingId, clientId, userId);
|
||||
return new_tracker;
|
||||
}
|
||||
|
||||
|
||||
/* Clear and de-allocate a tracker */
|
||||
void removeTracker(UATracker_t* tracker){
|
||||
assert(NULL != tracker);
|
||||
cleanTracker(tracker);
|
||||
free(tracker);
|
||||
}
|
||||
|
||||
/* Wrapper: set up lifetime options on a tracker */
|
||||
void setParameters(UATracker_t* tracker, UAOptions_t* opts){
|
||||
setParameterStateList(tracker, UA_PERMANENT, opts->options);
|
||||
}
|
||||
|
||||
/* Wrapper: set up a single lifetime option on a tracker */
|
||||
void setParameter(UATracker_t* tracker, trackingField_t field, unsigned int slot_id, char* value){
|
||||
setParameterState(tracker, UA_PERMANENT, field, slot_id, value);
|
||||
}
|
||||
|
||||
/* Retrieve name and value for a given index (transcending ephemeral state to lifetime, if needed) */
|
||||
void getCurrentParameterValue(UATracker_t* tracker, unsigned int index, char** name, char** value){
|
||||
assert(NULL != tracker);
|
||||
|
||||
(*name) = tracker->ephemeral_parameters[ index ].name;
|
||||
(*value) = tracker->ephemeral_parameters[ index ].value;
|
||||
if(NULL == (*name) || NULL == (*value)){
|
||||
(*name) = tracker->lifetime_parameters[ index ].name;
|
||||
(*value) = tracker->lifetime_parameters[ index ].value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct a query-string based on tracker state */
|
||||
unsigned int assembleQueryString(UATracker_t* tracker, char* query, unsigned int offset){
|
||||
unsigned int i;
|
||||
char* name;
|
||||
char* value;
|
||||
int name_len;
|
||||
char* current;
|
||||
unsigned int value_len;
|
||||
|
||||
// Shortcut for client_id for more readable assertion below
|
||||
char* client_id = tracker->map_parameters[UA_CLIENT_ID];
|
||||
|
||||
|
||||
for(i = 0; i < UA_MAX_PARAMETERS; i++){
|
||||
|
||||
getCurrentParameterValue(tracker, i, & name, & value);
|
||||
|
||||
// Validate parameters given
|
||||
assert((name == client_id) ? (value != NULL) : 1);
|
||||
if(NULL == name || NULL == value) continue;
|
||||
|
||||
name_len = (int)strlen(name);
|
||||
value_len = (int)strlen(value);
|
||||
|
||||
if(i > 0){
|
||||
strncpy(query + offset, "&", 1);
|
||||
offset++;
|
||||
}
|
||||
|
||||
strncpy(query + offset, name, name_len);
|
||||
strncpy(query + offset + name_len, "=", 1);
|
||||
|
||||
/* Fill in the encoded values */
|
||||
current = (query + offset + name_len + 1);
|
||||
value_len = encodeURIComponent(value, current, value_len, (UA_MAX_QUERY_LEN - ((unsigned int)(current - query))));
|
||||
|
||||
|
||||
offset += (name_len + value_len + 1);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
/* Assemble a query from a tracker and send it through CURL */
|
||||
void queueTracking(UATracker_t* tracker){
|
||||
assert(NULL != tracker);
|
||||
assert((*tracker).__configured__ == UA_MEM_MAGIC_CONFIG);
|
||||
|
||||
unsigned int query_len;
|
||||
char* query = tracker->query;
|
||||
memset(query, 0, UA_MAX_QUERY_LEN);
|
||||
query_len = assembleQueryString(tracker, query, 0);
|
||||
|
||||
HTTPenqueue(& tracker->queue, UA_ENDPOINT, tracker->user_agent, query, query_len);
|
||||
}
|
||||
|
||||
/* Prepare ephemeral state on a tracker and dispatch its query */
|
||||
void sendTracking(UATracker_t* tracker, trackingType_t type, UAOptions_t* opts){
|
||||
assert(NULL != tracker);
|
||||
assert((*tracker).__configured__ == UA_MEM_MAGIC_CONFIG);
|
||||
|
||||
|
||||
if(NULL != opts){
|
||||
setParameterStateList(tracker, UA_EPHEMERAL, opts->options);
|
||||
}
|
||||
|
||||
setParameterState(tracker,
|
||||
UA_EPHEMERAL, UA_TRACKING_TYPE, 0,
|
||||
getTrackingType(tracker, type)
|
||||
);
|
||||
|
||||
queueTracking(tracker);
|
||||
|
||||
if(getTrackerOption(tracker, UA_OPTION_QUEUE) == 0){
|
||||
HTTPflush(& tracker->queue);
|
||||
}
|
||||
|
||||
|
||||
resetQuery(tracker);
|
||||
|
||||
}
|
||||
|
||||
|
||||
244
Source/ThirdParty/UniversalAnalytics/universal-analytics.h
vendored
Normal file
244
Source/ThirdParty/UniversalAnalytics/universal-analytics.h
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
/******************************************************************************
|
||||
* Universal Analytics for C
|
||||
* Copyright (c) 2013, Analytics Pros
|
||||
*
|
||||
* This project is free software, distributed under the BSD license.
|
||||
* Analytics Pros offers consulting and integration services if your firm needs
|
||||
* assistance in strategy, implementation, or auditing existing work.
|
||||
******************************************************************************/
|
||||
|
||||
/* Header guard, prevent multiple definition */
|
||||
#ifndef UNIVERSALANALYTICS_HEADER_GUARD
|
||||
#define UNIVERSALANALYTICS_HEADER_GUARD 1
|
||||
|
||||
#include "http.h"
|
||||
#include "string/encode.h"
|
||||
|
||||
/* These definitions are primarily for planning memory allocation and loop sentinels;
|
||||
* eventually they'll be converted to enums... */
|
||||
#define UA_MAX_TYPES 8
|
||||
#define UA_MAX_FIELD_INDEX 69
|
||||
#define UA_MAX_CUSTOM_DIMENSION 200
|
||||
#define UA_MAX_CUSTOM_METRIC 200
|
||||
#define UA_START_CDIMENSIONS 57
|
||||
#define UA_START_CMETRICS 257
|
||||
#define UA_MAX_PARAMETERS (UA_MAX_FIELD_INDEX + UA_MAX_CUSTOM_DIMENSION + UA_MAX_CUSTOM_METRIC)
|
||||
#define UA_CUSTOM_PARAM_LEN 6
|
||||
#define UA_CUSTOM_PARAM_BUFFER ((UA_MAX_CUSTOM_DIMENSION + UA_MAX_CUSTOM_METRIC) * UA_CUSTOM_PARAM_LEN)
|
||||
#define UA_MAX_TRACKER_OPTION 1
|
||||
|
||||
|
||||
/* Boolean aliases for precise evaluation */
|
||||
typedef enum {
|
||||
UA_FALSE = 0,
|
||||
UA_TRUE = 1
|
||||
} UABoolean_t;
|
||||
|
||||
|
||||
/* Tracking types
|
||||
* These signify pageviews, events, transactions, etc.
|
||||
* Some behaviors (e.g. required parameters) may be altered by
|
||||
* this option (in future versions).
|
||||
*/
|
||||
typedef enum trackingType {
|
||||
UA_PAGEVIEW = 0,
|
||||
UA_APPVIEW,
|
||||
UA_SCREENVIEW,
|
||||
UA_EVENT,
|
||||
UA_TRANSACTION,
|
||||
UA_TRANSACTION_ITEM,
|
||||
UA_TIMING,
|
||||
UA_SOCIAL,
|
||||
UA_EXCEPTION
|
||||
} trackingType_t;
|
||||
|
||||
/* Tracking fields
|
||||
* These represent named parameters on the resulting URL query
|
||||
* sent to Google Analytics servers. They act as indices into
|
||||
* the array of parameter nodes for URL composition.
|
||||
*/
|
||||
typedef enum trackingField {
|
||||
UA_TRACKING_TYPE = 0,
|
||||
UA_VERSION_NUMBER,
|
||||
UA_TRACKING_ID, /* string like UA-XXXXX-Y */
|
||||
UA_CLIENT_ID,
|
||||
UA_USER_ID,
|
||||
UA_ANONYMIZE_IP,
|
||||
UA_DOCUMENT_PATH,
|
||||
UA_DOCUMENT_TITLE,
|
||||
UA_DOCUMENT_LOCATION,
|
||||
UA_DOCUMENT_HOSTNAME,
|
||||
UA_DOCUMENT_REFERRER,
|
||||
UA_DOCUMENT_ENCODING,
|
||||
UA_QUEUE_TIME_MS,
|
||||
UA_CACHE_BUSTER,
|
||||
UA_SESSION_CONTROL,
|
||||
UA_CAMPAIGN_NAME,
|
||||
UA_CAMPAIGN_SOURCE,
|
||||
UA_CAMPAIGN_MEDIUM,
|
||||
UA_CAMPAIGN_KEYWORD,
|
||||
UA_CAMPAIGN_CONTENT,
|
||||
UA_CAMPAIGN_ID,
|
||||
UA_SCREEN_RESOLUTION,
|
||||
UA_VIEWPORT_SIZE,
|
||||
UA_SCREEN_COLORS,
|
||||
UA_USER_LANGUAGE,
|
||||
UA_USER_AGENT,
|
||||
UA_APP_NAME,
|
||||
UA_APP_VERSION,
|
||||
UA_APP_ID,
|
||||
UA_APP_INSTALLER_ID,
|
||||
UA_CONTENT_DESCRIPTION,
|
||||
UA_SCREEN_NAME,
|
||||
UA_EVENT_CATEGORY,
|
||||
UA_EVENT_ACTION,
|
||||
UA_EVENT_LABEL,
|
||||
UA_EVENT_VALUE,
|
||||
UA_NON_INTERACTIVE,
|
||||
UA_SOCIAL_ACTION,
|
||||
UA_SOCIAL_NETWORK,
|
||||
UA_SOCIAL_TARGET,
|
||||
UA_EXCEPTION_DESCRIPTION,
|
||||
UA_EXCEPTION_FATAL,
|
||||
UA_TRANSACTION_ID,
|
||||
UA_TRANSACTION_AFFILIATION,
|
||||
UA_TRANSACTION_REVENUE,
|
||||
UA_TRANSACTION_SHIPPING,
|
||||
UA_TRANSACTION_TAX,
|
||||
UA_TRANSACTION_CURRENCY,
|
||||
UA_CURRENCY_CODE,
|
||||
UA_ITEM_CODE,
|
||||
UA_ITEM_NAME,
|
||||
UA_ITEM_VARIATION,
|
||||
UA_ITEM_CATEGORY,
|
||||
UA_ITEM_PRICE,
|
||||
UA_ITEM_QUANTITY,
|
||||
UA_TIMING_CATEGORY,
|
||||
UA_TIMING_VARIABLE,
|
||||
UA_TIMING_LABEL,
|
||||
UA_TIMING_TIME,
|
||||
UA_TIMING_DNS,
|
||||
UA_TIMING_PAGE_LOAD,
|
||||
UA_TIMING_REDIRECT,
|
||||
UA_TIMING_TCP_CONNECT,
|
||||
UA_TIMING_SERVER_RESPONSE,
|
||||
UA_ADWORDS_ID,
|
||||
UA_DISPLAY_AD_ID,
|
||||
UA_LINK_ID,
|
||||
UA_JAVA_ENABLED,
|
||||
UA_FLASH_VERSION,
|
||||
UA_CUSTOM_DIMENSION,
|
||||
UA_CUSTOM_METRIC
|
||||
} trackingField_t;
|
||||
|
||||
|
||||
/* Name/Value pair with slot ID for URL composition */
|
||||
typedef struct UAParameter_t {
|
||||
trackingField_t field;
|
||||
unsigned int slot_id;
|
||||
char* name;
|
||||
char* value;
|
||||
} UAParameter_t;
|
||||
|
||||
/* Flag to specify which level of tracker state to update */
|
||||
typedef enum stateScopeFlag_t {
|
||||
UA_PERMANENT = 0,
|
||||
UA_EPHEMERAL = 1
|
||||
} stateScopeFlag_t;
|
||||
|
||||
/* Configuration flags */
|
||||
typedef enum UATrackerOption_t {
|
||||
UA_OPTION_QUEUE = 0
|
||||
} UATrackerOption_t;
|
||||
|
||||
|
||||
/* Tracker layout intended to maximize stack allocation and
|
||||
* minimize heap/dynamic allocation */
|
||||
typedef struct UATracker_t {
|
||||
int __configured__;
|
||||
|
||||
/* Configuration flags */
|
||||
int options[ UA_MAX_TRACKER_OPTION ];
|
||||
|
||||
/* State maps for the tracker's resulting parameter values */
|
||||
struct UAParameter_t lifetime_parameters[ UA_MAX_PARAMETERS ];
|
||||
struct UAParameter_t ephemeral_parameters[ UA_MAX_PARAMETERS ];
|
||||
|
||||
/* Custom parameter names (e.g. cm1, cm199, cd1, cd199).
|
||||
* These are dynamically populated during tracker initialization
|
||||
* and linked in pointer-arrays below; this merely allocates
|
||||
* space (statically) as a component of the tracker */
|
||||
char map_custom[ UA_CUSTOM_PARAM_BUFFER ];
|
||||
|
||||
/* Standard parameter names (e.g. cid, tid, ea, ec...)
|
||||
* These are populated in stack space by |populateParameterNames|
|
||||
* during tracker initialization */
|
||||
char* map_parameters[ UA_MAX_PARAMETERS ];
|
||||
|
||||
/* Standard tracking type names (e.g. pageview, event, etc)
|
||||
* These are populated in stack space by |populateTypeNames|
|
||||
* during tracker initialization */
|
||||
char* map_types[ UA_MAX_TYPES ];
|
||||
|
||||
/* Placeholder for HTTP "User-Agent" header */
|
||||
const char* user_agent;
|
||||
|
||||
/* Stash space for the query strings generated through |sendTracking| */
|
||||
char query[ UA_MAX_QUERY_LEN ];
|
||||
int query_len;
|
||||
|
||||
/* HTTP handler (from http.h) */
|
||||
struct HTTPQueue_t queue;
|
||||
|
||||
} UATracker_t;
|
||||
|
||||
|
||||
/* Field/Value pairs with slot ID for convenient static specification */
|
||||
typedef struct UAOptionNode_t {
|
||||
trackingField_t field;
|
||||
unsigned int slot_id;
|
||||
char* value;
|
||||
} UAOptionNode_t;
|
||||
|
||||
/* List of options (field/value pairs with slot ID */
|
||||
typedef struct UAOptions_t {
|
||||
struct UAOptionNode_t options[ UA_MAX_PARAMETERS ];
|
||||
} UAOptions_t;
|
||||
|
||||
|
||||
|
||||
/* Other shortcuts for external interfaces */
|
||||
typedef UATracker_t* UATracker;
|
||||
typedef UAParameter_t UAParameter;
|
||||
typedef UAOptions_t UASettings;
|
||||
typedef UAOptions_t UAOptions;
|
||||
|
||||
|
||||
/* Creates Google Analytics tracker state objects */
|
||||
UATracker createTracker(char* trackingId, char* clientId, char* userId);
|
||||
|
||||
/* Initialize tracker state */
|
||||
void initTracker(UATracker tracker, char* trackingId, char* clientId, char* userId);
|
||||
|
||||
/* Set flags to tune the funcionality of the tracker */
|
||||
void setTrackerOption(UATracker tracker, UATrackerOption_t option, int value);
|
||||
|
||||
/* Stores option-values for the life of the tracker */
|
||||
void setParameters(UATracker tracker, UAOptions_t* opts);
|
||||
|
||||
/* Store a single option-value pair */
|
||||
void setParameter(UATracker tracker, trackingField_t type, unsigned int slot_id, char* value);
|
||||
|
||||
/* Processes tracker state with a tracking type and ephemeral options
|
||||
* Dispatches resulting query to Google Analytics */
|
||||
void sendTracking(UATracker state, trackingType_t type, UAOptions_t* opts);
|
||||
|
||||
/* Safely wipe tracker state without free() */
|
||||
void cleanTracker(UATracker);
|
||||
|
||||
/* Clears tracker memory & free()s all allocated heap space */
|
||||
void removeTracker(UATracker);
|
||||
|
||||
|
||||
|
||||
#endif /* UNIVERSALANALYTICS_HEADER_GUARD */
|
||||
Reference in New Issue
Block a user