diff options
author | Trumeet <yuuta@yuuta.moe> | 2022-07-23 11:03:20 -0700 |
---|---|---|
committer | Trumeet <yuuta@yuuta.moe> | 2022-07-23 11:03:20 -0700 |
commit | 6c49e2e93b23defd51d4b342baad5a9c3f843ea1 (patch) | |
tree | ccf1c90934571fe9472c85ea86ee1c5112ce3e65 /client/libacron/README.md | |
parent | 4337729c2fa77871e3b10cbe329f286c01ddc01f (diff) | |
download | acron-6c49e2e93b23defd51d4b342baad5a9c3f843ea1.tar acron-6c49e2e93b23defd51d4b342baad5a9c3f843ea1.tar.gz acron-6c49e2e93b23defd51d4b342baad5a9c3f843ea1.tar.bz2 acron-6c49e2e93b23defd51d4b342baad5a9c3f843ea1.zip |
feat(libacron/acronc): delegate socket IO to the client
API:CHANGE
Signed-off-by: Trumeet <yuuta@yuuta.moe>
Diffstat (limited to 'client/libacron/README.md')
-rw-r--r-- | client/libacron/README.md | 69 |
1 files changed, 62 insertions, 7 deletions
diff --git a/client/libacron/README.md b/client/libacron/README.md index e5ed81b..09e36dc 100644 --- a/client/libacron/README.md +++ b/client/libacron/README.md @@ -164,6 +164,22 @@ pass this pointer as-is when making connections or disconnecting. Every thread can have multiple connections simultaneously. +In addition, the client is required to provide its own socket IO implementations due to: + +1. Cross-platform is easier. +2. It is easier for users to supply their own async IO mechanism. + +The client needs to establish a socket connection before calling ac_connect. It should also +supply the pointer to its socket identifier (anything is accepted: libac only needs a pointer) to +`ac_connection_parameters`. A typical type is `* int` (pointer to socket fd). + +The client also needs to supply its own `on_send` function. libac will call that function when it +needs to write anything to the socket. When calling that function, the socket pointer will be passed +as-is. + +No worries, `acronc/net.c` provides a ready-to-use example of cross-platform (Unix and Windows) blocking +socket client. See `acronc/main.c` for more details. + ```c void *connection = NULL; int r; @@ -172,40 +188,79 @@ ac_connection_parameters_t args = { .port = 25575, .version = 0, .id = "1", - .token = "123" + .token = "123", + .on_send = /* TODO: on_send callback function */, + .socket = NULL }; +int socket = /* TODO: Connect to the socket. */; +args.socket = &socket; if ((r = ac_connect(args, &connection))) { return r; } /* Listen or make requests. */ ``` -Then, the program can listen for responses or events: +Upon `ac_connect`, libac only does a little to initialize the connection (e. g. write initial +handshake request to the socket). The handshake is not yet completed, and the client cannot send +requests yet. To display the state, libac provides a function called `ac_get_state()` which outputs +the current state to the connection (`AC_STATE_INIT`, `AC_STATE_READY` or `AC_STATE_CLOSED`). +A common usage is to loop `ac_receive` (see below) infinitely after `ac_connect` until the state +changes from `AC_STATE_INIT` to `AC_STATE_READY`, where `ac_request` is allowd and valid data will +return from `ac_receive`. + +Note: if the state changed to `AC_STATE_CLOSED` within `ac_receive`, this is likely due to an abnormal +termination of the connection. In this case, `ac_receive` will return `AC_E_NET`. + +Then, the program can listen for responses or events. +The client should do its own magic to receive from socket and +supply `ac_receive` with a buffer and size. ```c ac_obj_t *obj = NULL; -while (!interrupted || !(r = ac_receive(connection, &obj))) { +uint8_t buffer[1000U]; +size_t bytes; +/* TODO: recv() */ +while (!(r = ac_receive(connection, buffer, bytes, &obj))) { /* The obj is now referencing to a library allocated event or response. */ /* Do things with the event or response. */ ac_obj_free(obj); } ``` -The program can make requests using `ac_request()`. ~~This function can -be called from any thread (not specific to the listening one), but any thread -calling this function must also call `ac_init()` first.~~ **On the roadmap.** +The program can make requests using `ac_request()`: + +```c +ac_config_t conf = { + .name = "acronc" +}; +ac_request_cmd_t req = { + .type = AC_REQUEST_CMD, + .id = 100, + .config = &conf, + .cmd = "say Hi" +}; +ac_request(connection, (ac_request_t *) &req)); +``` Finally, when done, call `ac_disconnect()`. It will close the socket and free the `connection` parameter. The `connection` pointer after the method call is undefined. +The client must manually close its socket after calling `ac_disconnect()`. > **Notes**: > -> Only `ws://` is supported at this time. `wss://` support is +> Only unencrypted WebSocket is supported at this time. `wss://` support is > on the roadmap. Read more: `acronc/main.c` example client. +#### Connection Threading + +libac reads stores some state in the connection object upon each function call. Therefore, +it is the caller's responsibility to guard the whole connection with a mutex. libac does not +provide that because this may limit the flexibility. After locking, it is safe to call the +connection-related functions from any threads. + ## Roadmap * Make unit tests |