Files
coms/server/src/api.c
2026-03-11 00:27:19 -04:00

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;
}