diff --git a/common/include/request.h b/common/include/request.h new file mode 100644 index 0000000..8442ab5 --- /dev/null +++ b/common/include/request.h @@ -0,0 +1,54 @@ +#ifndef COMMON_REQUEST_H +#define COMMON_REQUEST_H + +#include + +#include "error.h" +#include "world.h" + +// ### REQUEST TYPES ### // + +enum request_type_t { + REQUEST_NONE, + REQUEST_GET_WORLD_DATA, +}; + + +struct request_body_get_world_data_t { + size_t world_id; +}; + + +struct request_t { + enum request_type_t type; + void *body; + // The body's type depends on the request's type +}; + + +enum error_t request_serialise_str(struct request_t const *, char const **); +enum error_t request_deserialise_str(struct request_t *, char const *); + +enum error_t request_serialise_buf(struct request_t const *, char *, size_t); + + +// ### RESPONSE TYPES ### // + +struct response_body_get_world_data_t { + struct world_t world; +}; + + +struct response_t { + bool success; + void *body; + // The body's type depends on the request's type +}; + + +enum error_t response_serialise_str(struct response_t const *, char const **); +enum error_t response_deserialise_str(struct response_t *, char const *); + +enum error_t response_serialise_buf(struct response_t const *, char *, size_t); + +#endif diff --git a/common/src/request.c b/common/src/request.c new file mode 100644 index 0000000..c615d90 --- /dev/null +++ b/common/src/request.c @@ -0,0 +1,252 @@ +// request.c + +#include +#include + +#include "request.h" + +// Request Format Strings +static char const *REQUEST_JSON_FMT = "{si, so}"; + +static char const *REQUEST_BODY_GET_WORLD_DATA_JSON_FMT = "{sI}"; + +// Response Format Strings + + +static enum error_t request_serialise_body_get_world_data( + struct request_body_get_world_data_t const *self, + struct json_t **jsonptr +) { + assert(self != NULL); + assert(jsonptr != NULL); + + struct json_t *json = json_pack(REQUEST_BODY_GET_WORLD_DATA_JSON_FMT, + "world-id", self->world_id + ); + + if (json == NULL) return ERR_JSON_SERIALISE; + + *jsonptr = json; + return ERR_OK; +} + + +static enum error_t request_serialise_body( + struct request_t const *self, + struct json_t **jsonptr +) { + assert(self != NULL); + assert(jsonptr != NULL); + + switch (self->type) { + case REQUEST_GET_WORLD_DATA: + return request_serialise_body_get_world_data(self->body, jsonptr); + + default: return ERR_JSON_SERIALISE; + } + return ERR_OK; +} + + +static enum error_t request_serialise_parts( + struct json_t *body_json, int type, + struct json_t **jsonptr +) { + assert(body_json != NULL); + assert(jsonptr != NULL); + + struct json_t *json = json_pack(REQUEST_JSON_FMT, + "request-code", type, + "parameters", body_json + ); + + if (json == NULL) return ERR_JSON_SERIALISE; + + *jsonptr = json; + return ERR_OK; +} + + +static enum error_t request_serialise( + struct request_t const *self, + struct json_t **jsonptr +) { + assert(self != NULL); + assert(jsonptr != NULL); + + // Serialise request body + struct json_t *body_json = NULL; + enum error_t err = request_serialise_body(self, &body_json); + if (err != ERR_OK) return err; + + // Serialise full structure + struct json_t *request_json = NULL; + err = request_serialise_parts(body_json, self->type, &request_json); + if (err != ERR_OK) { + json_decref(body_json); + return err; + } + + *jsonptr = request_json; + return ERR_OK; +} + + +enum error_t request_serialise_str( + struct request_t const *self, + char const **strptr +) { + assert(self != NULL); + assert(strptr != NULL); + + struct json_t *json = NULL; + enum error_t err = request_serialise(self, &json); + if (err != ERR_OK) return err; + + const char *str = json_dumps(json, 0); + if (str == NULL) { + json_decref(json); + return ERR_JSON_SERIALISE; + } + + json_decref(json); + + *strptr = str; + return ERR_OK; +} + + +enum error_t request_serialise_buf( + struct request_t const *self, + char *buf, size_t len +) { + assert(self != NULL); + assert(buf != NULL); + assert(len > 0); + + struct json_t *json = NULL; + enum error_t err = request_serialise(self, &json); + if (err != ERR_OK) return err; + + size_t bytes_written = json_dumpb(json, buf, len, 0); + if (bytes_written == 0) { + json_decref(json); + return ERR_JSON_SERIALISE; + } + + json_decref(json); + return ERR_OK; +} + + +static enum error_t request_deserialise_parts( + struct json_t **body_json, + enum request_type_t *type, + struct json_t *json +) { + assert(body_json != NULL); + assert(type != NULL); + assert(json != NULL); + + int err = json_unpack(json, REQUEST_JSON_FMT, + "request-code", type, + "parameters", body_json + ); + + if (err < 0) return ERR_JSON_DESERIALISE; + return ERR_OK; +} + + +static enum error_t request_deserialise_body_get_world_data( + struct request_body_get_world_data_t *self, + struct json_t *json +) { + assert(self != NULL); + assert(json != NULL); + + int err = json_unpack(json, REQUEST_BODY_GET_WORLD_DATA_JSON_FMT, + "world-id", &self->world_id + ); + + if (err < 0) return ERR_JSON_DESERIALISE; + return ERR_OK; +} + + +static enum error_t request_deserialise_body( + struct request_t *self, + struct json_t *json +) { + assert(self != NULL); + assert(json != NULL); + + switch (self->type) { + case REQUEST_GET_WORLD_DATA: + self->body = malloc(sizeof(struct request_body_get_world_data_t)); + if (self->body == NULL) return ERR_ALLOC; + + return request_deserialise_body_get_world_data(self->body, json); + + default: return ERR_JSON_SERIALISE; + } +} + + +static enum error_t request_deserialise( + struct request_t *self, + struct json_t *json +) { + assert(self != NULL); + assert(json != NULL); + + struct request_t temp_request = { 0 }; + struct json_t *body_json = NULL; + + enum error_t err = request_deserialise_parts( + &body_json, &temp_request.type, json + ); + if (err != ERR_OK) return err; + + err = request_deserialise_body(&temp_request, body_json); + if (err != ERR_OK) { + json_decref(body_json); + return err; + } + + *self = temp_request; + return ERR_OK; +} + + +enum error_t request_deserialise_str(struct request_t *self, char const *str) { + assert(self != NULL); + assert(str != NULL); + + struct json_t *json = json_loads(str, 0, NULL); + if (json == NULL) return ERR_JSON_DESERIALISE; + + enum error_t err = request_deserialise(self, json); + if (err != ERR_OK) { + json_decref(json); + return err; + } + + json_decref(json); + return ERR_OK; +} + + +enum error_t response_serialise_str( + struct response_t const *self, + char const **strptr +); + + +enum error_t response_serialise_buf( + struct response_t const *self, + char *buf, size_t len +); + + +enum error_t response_deserialise_str(struct response_t *self, char const *str); diff --git a/common/src/world.c b/common/src/world.c index 1dcff81..f53e741 100644 --- a/common/src/world.c +++ b/common/src/world.c @@ -93,7 +93,7 @@ static enum error_t world_serialise_parts( struct json_t *world_json = json_pack(WORLD_JSON_FMT, "entities", entities_json, - "registered_entities", registered_entities_json, + "registered-entities", registered_entities_json, "height", height, "width", width ); @@ -158,7 +158,7 @@ static enum error_t world_deserialise_parts( int err = json_unpack(json, WORLD_JSON_FMT, "entities", entities_json, - "registered_entities", registered_entities_json, + "registered-entities", registered_entities_json, "height", height, "width", width ); @@ -262,10 +262,15 @@ enum error_t world_serialise_str(struct world_t *self, char const **strptr) { struct json_t *json; enum error_t err = world_serialise(self, &json); - if (err != ERR_OK) return ERR_JSON_SERIALISE; + if (err != ERR_OK) return err; const char *str = json_dumps(json, 0); - if (str == NULL) return ERR_JSON_SERIALISE; + if (str == NULL) { + json_decref(json); + return ERR_JSON_SERIALISE; + } + + json_decref(json); *strptr = str; return ERR_OK; @@ -279,11 +284,15 @@ enum error_t world_serialise_buf(struct world_t *self, char *buf, size_t len) { struct json_t *json; enum error_t err = world_serialise(self, &json); - if (err != ERR_OK) return ERR_JSON_SERIALISE; + if (err != ERR_OK) return err; size_t bytes_written = json_dumpb(json, buf, len, 0); - if (bytes_written == 0) return ERR_JSON_SERIALISE; + if (bytes_written == 0) { + json_decref(json); + return ERR_JSON_SERIALISE; + } + json_decref(json); return ERR_OK; } @@ -296,8 +305,12 @@ enum error_t world_deserialise_str(struct world_t *self, char const *str) { if (json == NULL) return ERR_JSON_DESERIALISE; enum error_t err = world_deserialise(self, json); - if (err != ERR_OK) return ERR_JSON_DESERIALISE; + if (err != ERR_OK) { + json_decref(json); + return err; + } + json_decref(json); return ERR_OK; } diff --git a/doc/DESIGN.gmi b/doc/DESIGN.gmi deleted file mode 100644 index 1d4becc..0000000 --- a/doc/DESIGN.gmi +++ /dev/null @@ -1,51 +0,0 @@ -# DESIGN -This document describes the design of this project. The main purpose is to describe the interface between the client and the server, but I might document other useful information here, too. - -## Client/Server Communication -All communication is done through JSON. - -### Client Requests -Clients can make requests to the server by sending a JSON object containing two fields: -* "request", which is a string of name of the request being made -* "parameters", which is an object whose structure depends on the request. It contains a named list of the request's parameters - -### Server Responses -Upon receiving and handling a request, the server will send a response object with the following fields: -* "success", a boolean that indicates whether the request succeeded -* "response", an object whose structure depends on the request. It contains data relevant to the request - -### Example Request and Response -An example request might look as follows: -``` -{ - "request": "create-world", - "parameters": { - "name": "test world", - "size": { - "height": 10, - "width": 15, - } - } -} -``` - -A success response might look like: -``` -{ - "success": true, - "response": { - "world-id": 69420 - } -} -``` - -Or, in the case of an error: -``` -{ - "success": false, - "response": { - "code": 69 - "message": "A world with this name already exists" - } -} -``` diff --git a/server/src/main.c b/server/src/main.c index 59bedfe..4afabff 100644 --- a/server/src/main.c +++ b/server/src/main.c @@ -9,6 +9,7 @@ #include #include +#include #include "opts.h" #include "sock.h" @@ -25,6 +26,29 @@ static void handle_signal(int signal_no) { enum error_t game_loop(struct data_t *data) { enum error_t err = ERR_OK; + // TEMP + struct request_body_get_world_data_t request_body = { 69 }; + struct request_t request = { REQUEST_GET_WORLD_DATA, &request_body }; + + char const *request_json_str = NULL; + err = request_serialise_str(&request, &request_json_str); + if (err) return err; + + printf("serialised request: %s\n", request_json_str); + + struct request_t request2 = { 0 }; + err = request_deserialise_str(&request2, request_json_str); + if (err) return err; + + struct request_body_get_world_data_t *request2_body = request2.body; + printf("deserialised request: (%d, %zu)\n", + request2.type, + request2_body->world_id + ); + free((void *)request_json_str); + + // TEMP + char obuf[8192] = { 0 }; err = world_serialise_buf(&data->world, obuf, 8192); if (err != ERR_OK) return err; diff --git a/server/src/request.c b/server/src/request.c new file mode 100644 index 0000000..f30b9cd --- /dev/null +++ b/server/src/request.c @@ -0,0 +1,3 @@ +// request.c + +#include "request.h" diff --git a/server/src/request.h b/server/src/request.h new file mode 100644 index 0000000..537d983 --- /dev/null +++ b/server/src/request.h @@ -0,0 +1,8 @@ +#ifndef REQUEST_H +#define REQUEST_H + +#include + +enum error_t handle_request(void); + +#endif