#include "include/api.h" #include #include #include #include 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; }