add track module

main
Dominik Madarász 2023-10-24 11:43:43 +02:00
parent 6a569424c4
commit 21420bb867
8 changed files with 602 additions and 0 deletions

View File

@ -2415,6 +2415,16 @@ GAMEPAD_GUID, GAMEPAD_NAME,
char* tcp_port(int); char* tcp_port(int);
int tcp_close(int); int tcp_close(int);
int tcp_debug(int); int tcp_debug(int);
int track_init(char const *host, char const *port);
int track_destroy(void);
int track_event(char const *event_id, char const *user_id, char const *json_payload);
int track_ident(char const *user_id, char const *traits);
int track_group(char const *user_id, char const *group_id, char const *traits);
typedef struct {
char const *key;
char const *val;
} track_prop;
int track_event_props(char const *event_id, char const *user_id, const track_prop *props);
enum { NETWORK_BIND = 2, NETWORK_CONNECT = 4, NETWORK_NOFAIL = 8 }; enum { NETWORK_BIND = 2, NETWORK_CONNECT = 4, NETWORK_NOFAIL = 8 };
void network_create(unsigned max_clients, const char *ip, const char *port, unsigned flags); void network_create(unsigned max_clients, const char *ip, const char *port, unsigned flags);
enum { NETWORK_SEND = 2, NETWORK_RECV = 4 }; enum { NETWORK_SEND = 2, NETWORK_RECV = 4 };

View File

@ -16490,6 +16490,67 @@ API int tcp_debug(int); // toggle traffic monitoring on/off for given socket
//API int tcp_crypt(int,uint64_t); // set shared secret //API int tcp_crypt(int,uint64_t); // set shared secret
#line 0 #line 0
#line 1 "engine/split/v4k_track.h"
#ifndef TRACK_SEND_BUFSIZE
#define TRACK_SEND_BUFSIZE 576
#endif
//~ Errors
#define TRACK_ERROR_INIT_FAIL 1
#define TRACK_ERROR_SOCKET_FAIL 2
#define TRACK_ERROR_SOCKET_INVALID 3
#define TRACK_ERROR_BUFFER_FULL 4
#define TRACK_ERROR_SEND_FAIL 5
#define TRACK_ERROR_INPUT_INVALID 6
/// Initialises telemetry and connects to the specified endpoint.
/// return: error code
/// host: IP address / domain of the endpoint
/// port: service name / port
/// see: track_event, track_ident, track_group
API int track_init(char const *host, char const *port);
/// Destroys the currently established telemetry socket.
/// return: error code
/// No parameters needed for this function.
API int track_destroy(void);
/// Sends an EVENT message to the server.
/// return: error code
/// event_id: Identifier for the event type.
/// user_id: Identifier for the user.
/// json_payload: JSON-formatted metadata for the event.
API int track_event(char const *event_id, char const *user_id, char const *json_payload);
/// Sends user identification to the server.
/// return: error code
/// user_id: Identifier for the user.
/// traits: JSON-formatted traits or attributes of the user.
API int track_ident(char const *user_id, char const *traits);
/// Associates a user to a group.
/// return: error code
/// user_id: Identifier for the user.
/// group_id: Identifier for the group.
/// traits: JSON-formatted traits or attributes of the group.
API int track_group(char const *user_id, char const *group_id, char const *traits);
//~ Event utilities
/// Structure to represent key-value pairs for event properties.
typedef struct {
char const *key;
char const *val;
} track_prop;
/// Sends an EVENT message with custom properties.
/// return: error code
/// event_id: Identifier for the event type.
/// user_id: Identifier for the user.
/// props: Array of key-value pairs. Terminates when key is set to NULL.
API int track_event_props(char const *event_id, char const *user_id, const track_prop *props);
#line 0
#line 1 "engine/split/v4k_netsync.h" #line 1 "engine/split/v4k_netsync.h"
// high-level, socket-less networking api. inspired by Quake, MPI and RenderBuckets theories. // high-level, socket-less networking api. inspired by Quake, MPI and RenderBuckets theories.
// - rlyeh, public domain // - rlyeh, public domain
@ -342467,6 +342528,143 @@ static void network_init() {
} }
#line 0 #line 0
#line 1 "engine/split/v4k_track.c"
static __thread int track__sock = -1;
//~ Lifecycle methods
int track_init(char const *host, char const *port) {
if (track__sock > -1) {
swrapClose(track__sock);
track__sock = -1;
}
track__sock = swrapSocket(SWRAP_UDP, SWRAP_CONNECT, SWRAP_DEFAULT, host, port);
if (track__sock == -1) {
return -TRACK_ERROR_SOCKET_FAIL;
}
return 0;
}
int track_destroy(void) {
if (track__sock > -1) swrapClose(track__sock);
track__sock = -1;
return 0;
}
//~ Buffer utilities
static __thread char track__buffer[TRACK_SEND_BUFSIZE+1];
static __thread int track__buffer_len = 0;
static __thread int track__errno = 0;
static void track__buffer_flush(void) {
track__buffer_len = 0;
}
static int track__buffer_appendc(char *buf, int *len, char const *str) {
int size = (int)strlen(str);
if (*len+size > TRACK_SEND_BUFSIZE)
return -TRACK_ERROR_BUFFER_FULL;
memcpy(buf+*len, str, size);
*len += size;
return 0;
}
#define TRACK__APPEND_SAFE_EX(buf, len, xx)\
track__errno = track__buffer_appendc(buf, len, xx);\
if (track__errno) return track__errno;
#define TRACK__APPEND_SAFE(xx)\
TRACK__APPEND_SAFE_EX(track__buffer, &track__buffer_len, xx);
//~ Event tracking
int track_event(char const *event_id, char const *user_id, char const *json_payload) {
if (track__sock == -1)
return -TRACK_ERROR_SOCKET_INVALID;
if (!event_id || !user_id || !json_payload)
return -TRACK_ERROR_INPUT_INVALID;
track__buffer_flush();
TRACK__APPEND_SAFE("{\"userId\":\"");
TRACK__APPEND_SAFE(user_id);
TRACK__APPEND_SAFE("\",\"event\":\"");
TRACK__APPEND_SAFE(event_id);
TRACK__APPEND_SAFE("\",\"properties\":");
TRACK__APPEND_SAFE(json_payload);
TRACK__APPEND_SAFE("}");
if (!swrapSend(track__sock, track__buffer, track__buffer_len))
return -TRACK_ERROR_SEND_FAIL;
return 0;
}
int track_ident(char const *user_id, char const *traits) {
if (track__sock == -1)
return -TRACK_ERROR_SOCKET_INVALID;
if (!user_id || !traits)
return -TRACK_ERROR_INPUT_INVALID;
track__buffer_flush();
TRACK__APPEND_SAFE("{\"userId\":\"");
TRACK__APPEND_SAFE(user_id);
TRACK__APPEND_SAFE("\",\"traits\":");
TRACK__APPEND_SAFE(traits);
TRACK__APPEND_SAFE("}");
if (!swrapSend(track__sock, track__buffer, track__buffer_len))
return -TRACK_ERROR_SEND_FAIL;
return 0;
}
int track_group(char const *user_id, char const *group_id, char const *traits) {
if (track__sock == -1)
return -TRACK_ERROR_SOCKET_INVALID;
if (!user_id || !group_id || !traits)
return -TRACK_ERROR_INPUT_INVALID;
track__buffer_flush();
TRACK__APPEND_SAFE("{\"userId\":\"");
TRACK__APPEND_SAFE(user_id);
TRACK__APPEND_SAFE("\",\"groupId\":\"");
TRACK__APPEND_SAFE(group_id);
TRACK__APPEND_SAFE("\",\"traits\":");
TRACK__APPEND_SAFE(traits);
TRACK__APPEND_SAFE("}");
if (!swrapSend(track__sock, track__buffer, track__buffer_len))
return -TRACK_ERROR_SEND_FAIL;
return 0;
}
int track_event_props(char const *event_id, char const *user_id, const track_prop *props) {
static char buf[TRACK_SEND_BUFSIZE+1] = {0};
int len = 0;
if (!props)
return track_event(event_id, user_id, "");
TRACK__APPEND_SAFE_EX(buf, &len, "{");
while (props->key) {
TRACK__APPEND_SAFE_EX(buf, &len, "\"");
TRACK__APPEND_SAFE_EX(buf, &len, props->key);
TRACK__APPEND_SAFE_EX(buf, &len, "\":");
TRACK__APPEND_SAFE_EX(buf, &len, props->val);
++props;
if (props->key) {
TRACK__APPEND_SAFE_EX(buf, &len, ",");
}
}
TRACK__APPEND_SAFE_EX(buf, &len, "}");
return track_event(event_id, user_id, buf);
}
#undef TRACK__APPEND_SAFE
#undef TRACK__APPEND_SAFE_EX
#line 0
#line 1 "engine/split/v4k_netsync.c" #line 1 "engine/split/v4k_netsync.c"
typedef void* (*rpc_function)(); typedef void* (*rpc_function)();

View File

@ -143,6 +143,8 @@ API void *ui_handle();
{{FILE:v4k_network.c}} {{FILE:v4k_network.c}}
{{FILE:v4k_track.c}}
{{FILE:v4k_netsync.c}} {{FILE:v4k_netsync.c}}
{{FILE:v4k_pack.c}} {{FILE:v4k_pack.c}}

View File

@ -133,6 +133,8 @@ extern "C" {
{{FILE:v4k_network.h}} {{FILE:v4k_network.h}}
{{FILE:v4k_track.h}}
{{FILE:v4k_netsync.h}} {{FILE:v4k_netsync.h}}
{{FILE:v4k_obj.h}} {{FILE:v4k_obj.h}}

View File

@ -0,0 +1,134 @@
static __thread int track__sock = -1;
//~ Lifecycle methods
int track_init(char const *host, char const *port) {
if (track__sock > -1) {
swrapClose(track__sock);
track__sock = -1;
}
track__sock = swrapSocket(SWRAP_UDP, SWRAP_CONNECT, SWRAP_DEFAULT, host, port);
if (track__sock == -1) {
return -TRACK_ERROR_SOCKET_FAIL;
}
return 0;
}
int track_destroy(void) {
if (track__sock > -1) swrapClose(track__sock);
track__sock = -1;
return 0;
}
//~ Buffer utilities
static __thread char track__buffer[TRACK_SEND_BUFSIZE+1];
static __thread int track__buffer_len = 0;
static __thread int track__errno = 0;
static void track__buffer_flush(void) {
track__buffer_len = 0;
}
static int track__buffer_appendc(char *buf, int *len, char const *str) {
int size = (int)strlen(str);
if (*len+size > TRACK_SEND_BUFSIZE)
return -TRACK_ERROR_BUFFER_FULL;
memcpy(buf+*len, str, size);
*len += size;
return 0;
}
#define TRACK__APPEND_SAFE_EX(buf, len, xx)\
track__errno = track__buffer_appendc(buf, len, xx);\
if (track__errno) return track__errno;
#define TRACK__APPEND_SAFE(xx)\
TRACK__APPEND_SAFE_EX(track__buffer, &track__buffer_len, xx);
//~ Event tracking
int track_event(char const *event_id, char const *user_id, char const *json_payload) {
if (track__sock == -1)
return -TRACK_ERROR_SOCKET_INVALID;
if (!event_id || !user_id || !json_payload)
return -TRACK_ERROR_INPUT_INVALID;
track__buffer_flush();
TRACK__APPEND_SAFE("{\"userId\":\"");
TRACK__APPEND_SAFE(user_id);
TRACK__APPEND_SAFE("\",\"event\":\"");
TRACK__APPEND_SAFE(event_id);
TRACK__APPEND_SAFE("\",\"properties\":");
TRACK__APPEND_SAFE(json_payload);
TRACK__APPEND_SAFE("}");
if (!swrapSend(track__sock, track__buffer, track__buffer_len))
return -TRACK_ERROR_SEND_FAIL;
return 0;
}
int track_ident(char const *user_id, char const *traits) {
if (track__sock == -1)
return -TRACK_ERROR_SOCKET_INVALID;
if (!user_id || !traits)
return -TRACK_ERROR_INPUT_INVALID;
track__buffer_flush();
TRACK__APPEND_SAFE("{\"userId\":\"");
TRACK__APPEND_SAFE(user_id);
TRACK__APPEND_SAFE("\",\"traits\":");
TRACK__APPEND_SAFE(traits);
TRACK__APPEND_SAFE("}");
if (!swrapSend(track__sock, track__buffer, track__buffer_len))
return -TRACK_ERROR_SEND_FAIL;
return 0;
}
int track_group(char const *user_id, char const *group_id, char const *traits) {
if (track__sock == -1)
return -TRACK_ERROR_SOCKET_INVALID;
if (!user_id || !group_id || !traits)
return -TRACK_ERROR_INPUT_INVALID;
track__buffer_flush();
TRACK__APPEND_SAFE("{\"userId\":\"");
TRACK__APPEND_SAFE(user_id);
TRACK__APPEND_SAFE("\",\"groupId\":\"");
TRACK__APPEND_SAFE(group_id);
TRACK__APPEND_SAFE("\",\"traits\":");
TRACK__APPEND_SAFE(traits);
TRACK__APPEND_SAFE("}");
if (!swrapSend(track__sock, track__buffer, track__buffer_len))
return -TRACK_ERROR_SEND_FAIL;
return 0;
}
int track_event_props(char const *event_id, char const *user_id, const track_prop *props) {
static char buf[TRACK_SEND_BUFSIZE+1] = {0};
int len = 0;
if (!props)
return track_event(event_id, user_id, "");
TRACK__APPEND_SAFE_EX(buf, &len, "{");
while (props->key) {
TRACK__APPEND_SAFE_EX(buf, &len, "\"");
TRACK__APPEND_SAFE_EX(buf, &len, props->key);
TRACK__APPEND_SAFE_EX(buf, &len, "\":");
TRACK__APPEND_SAFE_EX(buf, &len, props->val);
++props;
if (props->key) {
TRACK__APPEND_SAFE_EX(buf, &len, ",");
}
}
TRACK__APPEND_SAFE_EX(buf, &len, "}");
return track_event(event_id, user_id, buf);
}
#undef TRACK__APPEND_SAFE
#undef TRACK__APPEND_SAFE_EX

View File

@ -0,0 +1,58 @@
#ifndef TRACK_SEND_BUFSIZE
#define TRACK_SEND_BUFSIZE 576
#endif
//~ Errors
#define TRACK_ERROR_INIT_FAIL 1
#define TRACK_ERROR_SOCKET_FAIL 2
#define TRACK_ERROR_SOCKET_INVALID 3
#define TRACK_ERROR_BUFFER_FULL 4
#define TRACK_ERROR_SEND_FAIL 5
#define TRACK_ERROR_INPUT_INVALID 6
/// Initialises telemetry and connects to the specified endpoint.
/// return: error code
/// host: IP address / domain of the endpoint
/// port: service name / port
/// see: track_event, track_ident, track_group
API int track_init(char const *host, char const *port);
/// Destroys the currently established telemetry socket.
/// return: error code
/// No parameters needed for this function.
API int track_destroy(void);
/// Sends an EVENT message to the server.
/// return: error code
/// event_id: Identifier for the event type.
/// user_id: Identifier for the user.
/// json_payload: JSON-formatted metadata for the event.
API int track_event(char const *event_id, char const *user_id, char const *json_payload);
/// Sends user identification to the server.
/// return: error code
/// user_id: Identifier for the user.
/// traits: JSON-formatted traits or attributes of the user.
API int track_ident(char const *user_id, char const *traits);
/// Associates a user to a group.
/// return: error code
/// user_id: Identifier for the user.
/// group_id: Identifier for the group.
/// traits: JSON-formatted traits or attributes of the group.
API int track_group(char const *user_id, char const *group_id, char const *traits);
//~ Event utilities
/// Structure to represent key-value pairs for event properties.
typedef struct {
char const *key;
char const *val;
} track_prop;
/// Sends an EVENT message with custom properties.
/// return: error code
/// event_id: Identifier for the event type.
/// user_id: Identifier for the user.
/// props: Array of key-value pairs. Terminates when key is set to NULL.
API int track_event_props(char const *event_id, char const *user_id, const track_prop *props);

View File

@ -10579,6 +10579,143 @@ static void network_init() {
} }
#line 0 #line 0
#line 1 "engine/split/v4k_track.c"
static __thread int track__sock = -1;
//~ Lifecycle methods
int track_init(char const *host, char const *port) {
if (track__sock > -1) {
swrapClose(track__sock);
track__sock = -1;
}
track__sock = swrapSocket(SWRAP_UDP, SWRAP_CONNECT, SWRAP_DEFAULT, host, port);
if (track__sock == -1) {
return -TRACK_ERROR_SOCKET_FAIL;
}
return 0;
}
int track_destroy(void) {
if (track__sock > -1) swrapClose(track__sock);
track__sock = -1;
return 0;
}
//~ Buffer utilities
static __thread char track__buffer[TRACK_SEND_BUFSIZE+1];
static __thread int track__buffer_len = 0;
static __thread int track__errno = 0;
static void track__buffer_flush(void) {
track__buffer_len = 0;
}
static int track__buffer_appendc(char *buf, int *len, char const *str) {
int size = (int)strlen(str);
if (*len+size > TRACK_SEND_BUFSIZE)
return -TRACK_ERROR_BUFFER_FULL;
memcpy(buf+*len, str, size);
*len += size;
return 0;
}
#define TRACK__APPEND_SAFE_EX(buf, len, xx)\
track__errno = track__buffer_appendc(buf, len, xx);\
if (track__errno) return track__errno;
#define TRACK__APPEND_SAFE(xx)\
TRACK__APPEND_SAFE_EX(track__buffer, &track__buffer_len, xx);
//~ Event tracking
int track_event(char const *event_id, char const *user_id, char const *json_payload) {
if (track__sock == -1)
return -TRACK_ERROR_SOCKET_INVALID;
if (!event_id || !user_id || !json_payload)
return -TRACK_ERROR_INPUT_INVALID;
track__buffer_flush();
TRACK__APPEND_SAFE("{\"userId\":\"");
TRACK__APPEND_SAFE(user_id);
TRACK__APPEND_SAFE("\",\"event\":\"");
TRACK__APPEND_SAFE(event_id);
TRACK__APPEND_SAFE("\",\"properties\":");
TRACK__APPEND_SAFE(json_payload);
TRACK__APPEND_SAFE("}");
if (!swrapSend(track__sock, track__buffer, track__buffer_len))
return -TRACK_ERROR_SEND_FAIL;
return 0;
}
int track_ident(char const *user_id, char const *traits) {
if (track__sock == -1)
return -TRACK_ERROR_SOCKET_INVALID;
if (!user_id || !traits)
return -TRACK_ERROR_INPUT_INVALID;
track__buffer_flush();
TRACK__APPEND_SAFE("{\"userId\":\"");
TRACK__APPEND_SAFE(user_id);
TRACK__APPEND_SAFE("\",\"traits\":");
TRACK__APPEND_SAFE(traits);
TRACK__APPEND_SAFE("}");
if (!swrapSend(track__sock, track__buffer, track__buffer_len))
return -TRACK_ERROR_SEND_FAIL;
return 0;
}
int track_group(char const *user_id, char const *group_id, char const *traits) {
if (track__sock == -1)
return -TRACK_ERROR_SOCKET_INVALID;
if (!user_id || !group_id || !traits)
return -TRACK_ERROR_INPUT_INVALID;
track__buffer_flush();
TRACK__APPEND_SAFE("{\"userId\":\"");
TRACK__APPEND_SAFE(user_id);
TRACK__APPEND_SAFE("\",\"groupId\":\"");
TRACK__APPEND_SAFE(group_id);
TRACK__APPEND_SAFE("\",\"traits\":");
TRACK__APPEND_SAFE(traits);
TRACK__APPEND_SAFE("}");
if (!swrapSend(track__sock, track__buffer, track__buffer_len))
return -TRACK_ERROR_SEND_FAIL;
return 0;
}
int track_event_props(char const *event_id, char const *user_id, const track_prop *props) {
static char buf[TRACK_SEND_BUFSIZE+1] = {0};
int len = 0;
if (!props)
return track_event(event_id, user_id, "");
TRACK__APPEND_SAFE_EX(buf, &len, "{");
while (props->key) {
TRACK__APPEND_SAFE_EX(buf, &len, "\"");
TRACK__APPEND_SAFE_EX(buf, &len, props->key);
TRACK__APPEND_SAFE_EX(buf, &len, "\":");
TRACK__APPEND_SAFE_EX(buf, &len, props->val);
++props;
if (props->key) {
TRACK__APPEND_SAFE_EX(buf, &len, ",");
}
}
TRACK__APPEND_SAFE_EX(buf, &len, "}");
return track_event(event_id, user_id, buf);
}
#undef TRACK__APPEND_SAFE
#undef TRACK__APPEND_SAFE_EX
#line 0
#line 1 "engine/split/v4k_netsync.c" #line 1 "engine/split/v4k_netsync.c"
typedef void* (*rpc_function)(); typedef void* (*rpc_function)();

View File

@ -2557,6 +2557,67 @@ API int tcp_debug(int); // toggle traffic monitoring on/off for given socket
//API int tcp_crypt(int,uint64_t); // set shared secret //API int tcp_crypt(int,uint64_t); // set shared secret
#line 0 #line 0
#line 1 "engine/split/v4k_track.h"
#ifndef TRACK_SEND_BUFSIZE
#define TRACK_SEND_BUFSIZE 576
#endif
//~ Errors
#define TRACK_ERROR_INIT_FAIL 1
#define TRACK_ERROR_SOCKET_FAIL 2
#define TRACK_ERROR_SOCKET_INVALID 3
#define TRACK_ERROR_BUFFER_FULL 4
#define TRACK_ERROR_SEND_FAIL 5
#define TRACK_ERROR_INPUT_INVALID 6
/// Initialises telemetry and connects to the specified endpoint.
/// return: error code
/// host: IP address / domain of the endpoint
/// port: service name / port
/// see: track_event, track_ident, track_group
API int track_init(char const *host, char const *port);
/// Destroys the currently established telemetry socket.
/// return: error code
/// No parameters needed for this function.
API int track_destroy(void);
/// Sends an EVENT message to the server.
/// return: error code
/// event_id: Identifier for the event type.
/// user_id: Identifier for the user.
/// json_payload: JSON-formatted metadata for the event.
API int track_event(char const *event_id, char const *user_id, char const *json_payload);
/// Sends user identification to the server.
/// return: error code
/// user_id: Identifier for the user.
/// traits: JSON-formatted traits or attributes of the user.
API int track_ident(char const *user_id, char const *traits);
/// Associates a user to a group.
/// return: error code
/// user_id: Identifier for the user.
/// group_id: Identifier for the group.
/// traits: JSON-formatted traits or attributes of the group.
API int track_group(char const *user_id, char const *group_id, char const *traits);
//~ Event utilities
/// Structure to represent key-value pairs for event properties.
typedef struct {
char const *key;
char const *val;
} track_prop;
/// Sends an EVENT message with custom properties.
/// return: error code
/// event_id: Identifier for the event type.
/// user_id: Identifier for the user.
/// props: Array of key-value pairs. Terminates when key is set to NULL.
API int track_event_props(char const *event_id, char const *user_id, const track_prop *props);
#line 0
#line 1 "engine/split/v4k_netsync.h" #line 1 "engine/split/v4k_netsync.h"
// high-level, socket-less networking api. inspired by Quake, MPI and RenderBuckets theories. // high-level, socket-less networking api. inspired by Quake, MPI and RenderBuckets theories.
// - rlyeh, public domain // - rlyeh, public domain