aboutsummaryrefslogtreecommitdiff
path: root/client/libacron/README.md
diff options
context:
space:
mode:
authorTrumeet <yuuta@yuuta.moe>2022-07-23 11:03:20 -0700
committerTrumeet <yuuta@yuuta.moe>2022-07-23 11:03:20 -0700
commit6c49e2e93b23defd51d4b342baad5a9c3f843ea1 (patch)
treeccf1c90934571fe9472c85ea86ee1c5112ce3e65 /client/libacron/README.md
parent4337729c2fa77871e3b10cbe329f286c01ddc01f (diff)
downloadacron-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.md69
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