240 lines
8.6 KiB
C
240 lines
8.6 KiB
C
#include "include/api.h"
|
|
|
|
#include <inttypes.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <yyjson.h>
|
|
|
|
static const char* packet_type_strings[] = {
|
|
[PACKET_TYPE_JOIN] = "join",
|
|
[PACKET_TYPE_WELCOME] = "welcome",
|
|
[PACKET_TYPE_JOIN_EVT] = "join_evt",
|
|
[PACKET_TYPE_MSG] = "msg",
|
|
[PACKET_TYPE_MSG_EVT] = "msg_evt",
|
|
[PACKET_TYPE_NAME] = "name",
|
|
[PACKET_TYPE_NAME_EVT] = "name_evt",
|
|
[PACKET_TYPE_PING] = "ping",
|
|
[PACKET_TYPE_PONG] = "pong",
|
|
[PACKET_TYPE_MSG_ACK] = "msg_ack",
|
|
[PACKET_TYPE_NAME_ACK] = "name_ack",
|
|
[PACKET_TYPE_HISTORY_REQ] = "history_req",
|
|
[PACKET_TYPE_HISTORY_RES] = "history_res",
|
|
[PACKET_TYPE_LEAVE_EVT] = "leave_evt",
|
|
};
|
|
|
|
PacketType packet_type_parse(const char* type) {
|
|
for (int i = 0; i <= PACKET_TYPE_MAX; i++)
|
|
if (!strcmp(type, packet_type_strings[i])) return (PacketType)i;
|
|
|
|
return PACKET_TYPE_BAD;
|
|
}
|
|
|
|
Packet* packet_init(PacketType type, void* data) {
|
|
Packet* packet = malloc(sizeof(Packet));
|
|
if (!packet) return NULL;
|
|
|
|
packet->type = type;
|
|
packet->data = data;
|
|
|
|
return packet;
|
|
}
|
|
|
|
Packet* packet_init_safe(const char* type, const void* data) {
|
|
if (!data) return NULL;
|
|
|
|
PacketType t = packet_type_parse(type);
|
|
if (t == PACKET_TYPE_BAD) return NULL;
|
|
|
|
return packet_init(t, (void*)data);
|
|
}
|
|
|
|
// Per-packet-type encoders.
|
|
static void pack_welcome(
|
|
yyjson_mut_doc* doc, yyjson_mut_val* data, PacketWelcome* welcome
|
|
) {
|
|
yyjson_mut_obj_add_uint(doc, data, "id", welcome->id);
|
|
yyjson_mut_obj_add_int(doc, data, "onlinec", welcome->onlinec);
|
|
yyjson_mut_val* online = yyjson_mut_arr(doc);
|
|
for (size_t i = 0; i < welcome->onlinec; i++) {
|
|
yyjson_mut_val* u = yyjson_mut_obj(doc);
|
|
yyjson_mut_obj_add_uint(doc, u, "id", welcome->online[i].id);
|
|
if (welcome->online[i].name)
|
|
yyjson_mut_obj_add_str(doc, u, "name", *welcome->online[i].name);
|
|
else yyjson_mut_obj_add_str(doc, u, "name", "");
|
|
yyjson_mut_arr_add_val(online, u);
|
|
}
|
|
yyjson_mut_obj_add_val(doc, data, "online", online);
|
|
|
|
yyjson_mut_obj_add_int(doc, data, "historyc", welcome->historyc);
|
|
yyjson_mut_val* history = yyjson_mut_arr(doc);
|
|
for (size_t i = 0; i < welcome->historyc; i++) {
|
|
MsgData* m = welcome->history[i];
|
|
if (!m) continue;
|
|
yyjson_mut_val* msg = yyjson_mut_obj(doc);
|
|
yyjson_mut_obj_add_uint(doc, msg, "id", m->id);
|
|
yyjson_mut_val* auth = yyjson_mut_obj(doc);
|
|
yyjson_mut_obj_add_uint(doc, auth, "id", m->author.id);
|
|
if (m->author.name)
|
|
yyjson_mut_obj_add_str(doc, auth, "name", *m->author.name);
|
|
else yyjson_mut_obj_add_str(doc, auth, "name", "");
|
|
yyjson_mut_obj_add_val(doc, msg, "author", auth);
|
|
if (m->parent != UINT64_MAX)
|
|
yyjson_mut_obj_add_uint(doc, msg, "parent", m->parent);
|
|
else yyjson_mut_obj_add_null(doc, msg, "parent");
|
|
yyjson_mut_obj_add_str(doc, msg, "content", m->content);
|
|
yyjson_mut_obj_add_int(doc, msg, "timestamp", m->timestamp);
|
|
yyjson_mut_arr_add_val(history, msg);
|
|
}
|
|
yyjson_mut_obj_add_val(doc, data, "history", history);
|
|
}
|
|
|
|
static void
|
|
pack_msg_evt(yyjson_mut_doc* doc, yyjson_mut_val* data, PacketMsgEvt* msgevt) {
|
|
yyjson_mut_obj_add_uint(doc, data, "id", msgevt->id);
|
|
yyjson_mut_val* authordata = yyjson_mut_obj(doc);
|
|
yyjson_mut_obj_add_uint(doc, authordata, "id", msgevt->author.id);
|
|
yyjson_mut_obj_add_str(doc, authordata, "name", *msgevt->author.name);
|
|
yyjson_mut_obj_add_val(doc, data, "author", authordata);
|
|
if (msgevt->parent != UINT64_MAX) {
|
|
yyjson_mut_obj_add_uint(doc, data, "parent", msgevt->parent);
|
|
} else {
|
|
yyjson_mut_obj_add_null(doc, data, "parent");
|
|
}
|
|
yyjson_mut_obj_add_str(doc, data, "content", msgevt->content);
|
|
yyjson_mut_obj_add_int(doc, data, "timestamp", msgevt->timestamp);
|
|
}
|
|
|
|
static void pack_join_evt(
|
|
yyjson_mut_doc* doc, yyjson_mut_val* data, PacketJoinEvt* joinevt
|
|
) {
|
|
yyjson_mut_obj_add_uint(doc, data, "id", joinevt->id);
|
|
yyjson_mut_obj_add_str(doc, data, "name", *joinevt->name);
|
|
}
|
|
|
|
static void pack_name_evt(
|
|
yyjson_mut_doc* doc, yyjson_mut_val* data, PacketNameEvt* nameevt
|
|
) {
|
|
yyjson_mut_val* user = yyjson_mut_obj(doc);
|
|
yyjson_mut_obj_add_uint(doc, user, "id", nameevt->user.id);
|
|
yyjson_mut_obj_add_str(doc, user, "name", nameevt->old_name);
|
|
yyjson_mut_obj_add_val(doc, data, "user", user);
|
|
yyjson_mut_obj_add_str(doc, data, "new_name", nameevt->new_name);
|
|
}
|
|
|
|
static void pack_leave_evt(
|
|
yyjson_mut_doc* doc, yyjson_mut_val* data, PacketJoinEvt* leave
|
|
) {
|
|
yyjson_mut_obj_add_uint(doc, data, "id", leave->id);
|
|
yyjson_mut_obj_add_str(doc, data, "name", *leave->name);
|
|
}
|
|
|
|
static void
|
|
pack_ping(yyjson_mut_doc* doc, yyjson_mut_val* data, PacketPing* p) {
|
|
yyjson_mut_obj_add_uint(doc, data, "ts", p->ts);
|
|
}
|
|
|
|
static void
|
|
pack_msg_ack(yyjson_mut_doc* doc, yyjson_mut_val* data, PacketMsgAck* ack) {
|
|
yyjson_mut_obj_add_str(doc, data, "status", ack->status);
|
|
yyjson_mut_obj_add_uint(doc, data, "id", ack->id);
|
|
}
|
|
|
|
static void
|
|
pack_name_ack(yyjson_mut_doc* doc, yyjson_mut_val* data, PacketNameAck* ack) {
|
|
yyjson_mut_obj_add_str(doc, data, "status", ack->status);
|
|
yyjson_mut_obj_add_str(doc, data, "name", ack->name);
|
|
}
|
|
|
|
static void pack_history_res(
|
|
yyjson_mut_doc* doc, yyjson_mut_val* data, PacketHistoryRes* hist
|
|
) {
|
|
yyjson_mut_obj_add_str(doc, data, "room", hist->room);
|
|
yyjson_mut_obj_add_bool(doc, data, "has_more", hist->has_more);
|
|
yyjson_mut_obj_add_int(doc, data, "oldest_id", hist->oldest_id);
|
|
yyjson_mut_obj_add_int(doc, data, "historyc", hist->historyc);
|
|
yyjson_mut_val* history = yyjson_mut_arr(doc);
|
|
for (size_t i = 0; i < hist->historyc; i++) {
|
|
MsgData* m = hist->history[i];
|
|
if (!m) continue;
|
|
yyjson_mut_val* msg = yyjson_mut_obj(doc);
|
|
yyjson_mut_obj_add_uint(doc, msg, "id", m->id);
|
|
yyjson_mut_val* auth = yyjson_mut_obj(doc);
|
|
yyjson_mut_obj_add_uint(doc, auth, "id", m->author.id);
|
|
if (m->author.name)
|
|
yyjson_mut_obj_add_str(doc, auth, "name", *m->author.name);
|
|
else yyjson_mut_obj_add_str(doc, auth, "name", "");
|
|
yyjson_mut_obj_add_val(doc, msg, "author", auth);
|
|
if (m->parent != UINT64_MAX)
|
|
yyjson_mut_obj_add_uint(doc, msg, "parent", m->parent);
|
|
else yyjson_mut_obj_add_null(doc, msg, "parent");
|
|
yyjson_mut_obj_add_str(doc, msg, "content", m->content);
|
|
yyjson_mut_obj_add_int(doc, msg, "timestamp", m->timestamp);
|
|
yyjson_mut_arr_add_val(history, msg);
|
|
}
|
|
yyjson_mut_obj_add_val(doc, data, "history", history);
|
|
}
|
|
|
|
char* packet_string(Packet* packet, size_t* sz) {
|
|
yyjson_mut_doc* doc = yyjson_mut_doc_new(NULL);
|
|
|
|
// Create document root.
|
|
yyjson_mut_val* root = yyjson_mut_obj(doc);
|
|
yyjson_mut_doc_set_root(doc, root);
|
|
|
|
// Add the type field.
|
|
yyjson_mut_obj_add_str(
|
|
doc, root, "type", packet_type_strings[packet->type]
|
|
);
|
|
|
|
// Create the "data" field.
|
|
yyjson_mut_val* data = yyjson_mut_obj(doc);
|
|
|
|
switch (packet->type) {
|
|
case PACKET_TYPE_WELCOME:
|
|
pack_welcome(doc, data, (PacketWelcome*)packet->data);
|
|
break;
|
|
case PACKET_TYPE_MSG_EVT:
|
|
pack_msg_evt(doc, data, (PacketMsgEvt*)packet->data);
|
|
break;
|
|
case PACKET_TYPE_JOIN_EVT:
|
|
pack_join_evt(doc, data, (PacketJoinEvt*)packet->data);
|
|
break;
|
|
case PACKET_TYPE_LEAVE_EVT:
|
|
pack_leave_evt(doc, data, (PacketJoinEvt*)packet->data);
|
|
break;
|
|
case PACKET_TYPE_NAME_EVT:
|
|
pack_name_evt(doc, data, (PacketNameEvt*)packet->data);
|
|
break;
|
|
case PACKET_TYPE_PING:
|
|
pack_ping(doc, data, (PacketPing*)packet->data);
|
|
break;
|
|
case PACKET_TYPE_PONG:
|
|
pack_ping(doc, data, (PacketPing*)packet->data);
|
|
break;
|
|
case PACKET_TYPE_MSG_ACK:
|
|
pack_msg_ack(doc, data, (PacketMsgAck*)packet->data);
|
|
break;
|
|
case PACKET_TYPE_NAME_ACK:
|
|
pack_name_ack(doc, data, (PacketNameAck*)packet->data);
|
|
break;
|
|
case PACKET_TYPE_HISTORY_RES:
|
|
pack_history_res(doc, data, (PacketHistoryRes*)packet->data);
|
|
break;
|
|
default:
|
|
printf(
|
|
"Something's gone badly wrong. Trying to get string of "
|
|
"non-sending packet type %d. \n",
|
|
packet->type
|
|
);
|
|
exit(347);
|
|
}
|
|
|
|
// Add data field to root.
|
|
yyjson_mut_obj_add_val(doc, root, "data", data);
|
|
|
|
char* out = yyjson_mut_write(doc, 0, sz);
|
|
yyjson_mut_doc_free(doc);
|
|
|
|
return out;
|
|
}
|