aboutsummaryrefslogtreecommitdiff
path: root/client/libacron/README.md
blob: e5ed81b620234083e826f95874bfc1f89ae5f173 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# `libac`: Acron Client Library

A client library written in C, 
based on [json-c](https://github.com/json-c/json-c) and [wic](https://github.com/cjhdev/wic).

## Building

Requirements:

* `json-c` installed and using PkgConfig
* Git
* CMake
* A C11 or higher C compiler
* Connectivity to this git repository and `github.com`

To build on Unix:

```shell
git clone https://git.yuuta.moe/Minecraft/acron.git
cd acron
git submodule update --init
cd client/libacron/
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
DESTDIR=$(pwd)/install cmake --install .
```

The shared library will be at `libac.so` (`ac.dll` on Windows). The static library will be at `libac-static.a` (`ac-static.lib` on Windows).

The distributable headers are at `install/usr/local/include/libac/`.

To make debug builds, use the Debug build type. Debug builds will have ASAN enabled.

To build on Windows:

```batch
git clone https://git.yuuta.moe/Minecraft/acron.git
CD acron
git submodule update --init
CD client/libacron/
setup.bat
mkdir build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
```

## Usage

All functions begin with `ac_`. Include `libac.h`.


### Thread Safety

This library is single-threaded, meaning that all functions should be called on a 
dedicated thread. However, user may initialize the library on multiple threads and call
the functions on different threads without interfering each other.

### Error Handling

All error codes are at `common.h`. `AC_E_*` are library errors (generated by library routines);
`AC_ER_*` are remote errors (generated by the server), and you should match them with `ac_response_error.code`.

All libac functions return an integer value of the error code. `AC_E_OK(0)` indicates successful operation.

Any library function calls not following the document will return `AC_E_INVALID_REQUEST`.

### Struct Inheritance

All libac exported structs have a `uint8_t type` as its first member. It indicates the type of the object.
The type ID is globally unique and stable across upgrades.

Internally, the type is an unsigned 8-bit integer, with the first two bits indicating whether it is
an event, a response, or a request. The remaining 6 bits differentiates the type with others.

Library users usually do not need to care about the internal assignment of type IDs. Every exported struct
have its ID defined in the corresponding headers (e.g. `AC_RESPONSE_OK`). Macros like `AC_IS_EVENT` is also 
available (from `ids.h`).

Thus, the base definition of all libac structs is:

```c
/* ids.h */
typedef struct ac_obj {
    uint8_t type;
} ac_obj_t;
```

are classified in three types:

* Event: Server-initiated events. Do not have IDs. Base definition: `ac_event_t`.
```c
/* events.h */
typedef struct ac_event {
    uint8_t type;
} ac_event_t;
```
* Request: Program-allocated requests. Have a program-assigned ID. Base definition: `ac_request_t`.
```c
/* requests.h */
typedef struct ac_request {
    uint8_t type;
    int id;
} ac_request_t;
```
* Response: Responses to requests. Have the same ID as the request. Base definition: `ac_response_t`.
```c
/* requests.h */
typedef struct ac_response {
    uint8_t type;
    int id;
} ac_response_t;
```

### Struct Memory Management

For requests only, it is the program's responsibility to allocate them (on whether stack or heap) and 
assign the correct type, so libac can recognize them. The program should also free the request after making
`ac_request()` calls, as libac will not modify the request object:

```c
int list(void *connection) {
    /* Allocated on the stack: Freed upon return, not by libac. */
    ac_request_cmd cmd = {
            .type = AC_REQUEST_CMD,
            .id = 114514,
            .config = NULL,
            .cmd = "list"
    };
    int r = ac_request(connection, (ac_request_t *) &cmd);
    /* cmd is freed. */
    return r;
}
```

For events and responses, libac will allocate them internally, and the program should free them using 
`ac_obj_free(ac_obj_t)` function.

### Initialization

To initialize the library on the current thread, call: `ac_init()`:

```c
int main(void) {
    libac_config_t config = {
            .out = NULL, /* Error output stream. NULL to disable any error logging. */
            .tok = NULL
    }
    int r = ac_init(&config);
    if (r) return r;
}
```

When finished using libac on the thread, call `ac_free()`.

Any function call without `ac_init()` first will return `AC_E_NOT_INITIALIZED`.

### Making Connections

To connect to a server on the current thread, use `ac_connect()`.
It will output a `void *` opaque pointer referencing to the connection. Programs should
pass this pointer as-is when making connections or disconnecting.

Every thread can have multiple connections simultaneously.

```c
void *connection = NULL;
int r;
ac_connection_parameters_t args = {
        .host = "127.0.0.1",
        .port = 25575,
        .version = 0,
        .id = "1",
        .token = "123"
};
if ((r = ac_connect(args, &connection))) {
    return r;
}
/* Listen or make requests. */
```

Then, the program can listen for responses or events:

```c
ac_obj_t *obj = NULL;
while (!interrupted || !(r = ac_receive(connection, &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.**

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.

> **Notes**:
> 
> Only `ws://` is supported at this time. `wss://` support is
> on the roadmap.


Read more: `acronc/main.c` example client.

## Roadmap

* Make unit tests
* SSL support
* Calling `ac_request()` from any thread

## License

The libac library is licensed under LGPL-2.1-only. Other parts of Acron is still licensed under GPL-2.0-only.