diff options
Diffstat (limited to 'src/libclient')
| -rw-r--r-- | src/libclient/client.c | 98 | ||||
| -rw-r--r-- | src/libclient/client.h | 31 | ||||
| -rw-r--r-- | src/libclient/commands.h | 1 | ||||
| -rw-r--r-- | src/libclient/meson.build | 3 | ||||
| -rw-r--r-- | src/libclient/resource_client.c | 91 | ||||
| -rw-r--r-- | src/libclient/resource_client.h | 29 | ||||
| -rw-r--r-- | src/libclient/search.c | 31 | ||||
| -rw-r--r-- | src/libclient/search.h | 28 |
8 files changed, 312 insertions, 0 deletions
diff --git a/src/libclient/client.c b/src/libclient/client.c new file mode 100644 index 0000000..60998c6 --- /dev/null +++ b/src/libclient/client.c @@ -0,0 +1,98 @@ +#include "../tree/commands.h" +#include "../shoki/src/packet_ext.h" + +#include "client.h" + +static void identifed_callback(void *userdata, struct aki_packet *packet) +{ + struct camu_client *client = (struct camu_client *)userdata; + client->callback(client->userdata, CAMU_CLIENT_CONNECTED, NULL); + aki_packet_free(packet); +} + +static void connection_callback(void *userdata, struct aki_rpc_connection *conn) +{ + struct camu_client *client = (struct camu_client *)userdata; + client->conn = conn; + struct aki_packet *packet = aki_rpc_get_packet(&client->client, TREE_CMD_IDENTIFY); + aki_packet_write_u8(packet, TREE_CLIENT); + aki_packet_write_string(packet, &client->username); + aki_rpc_connection_command(client->conn, packet, identifed_callback, client); +} + +static void connection_closed_callback(void *userdata, struct aki_rpc_connection *conn) +{ + (void)userdata; + (void)conn; +} + +static u8 packet_pool_callback(void *userdata, struct aki_packet *packet) +{ + struct camu_client *client = (struct camu_client *)userdata; + aki_rpc_connection_command(client->conn, packet, packet->userdata, client); + return AKI_PACKET_POOL_NOP; +} + +bool camu_client_init(struct camu_client *client) +{ + aki_event_loop_init(&client->loop); + aki_packet_pool_init_ex(&client->pool, 0, &client->loop, + AKI_PACKET_POOL_MODE_PASSTHROUGH, packet_pool_callback, client); + return aki_rpc_init(&client->client, AKI_SOCKET_TCP, connection_callback, + connection_closed_callback, client); +} + +static aki_thread_result AKI_THREADCALL event_loop_thread(void *userdata) +{ + struct camu_client *client = (struct camu_client *)userdata; + aki_event_loop_run(&client->loop); + return 0; +} + +bool camu_client_login(struct camu_client *client, str *username, str *addr, s32 port, + void (*callback)(void *, u8, void *), void *userdata) +{ + al_str_clone(&client->username, username); + client->callback = callback; + client->userdata = userdata; + if (!aki_rpc_connect(&client->client, &client->loop, addr, port)) { + return false; + } + aki_thread_create(&client->thread, event_loop_thread, client); + return true; +} + +static void search_callback(void *userdata, struct aki_packet *packet) +{ + struct camu_client *client = (struct camu_client *)userdata; + struct camu_search_results *results = al_alloc_object(struct camu_search_results); + al_array_init(results->results); + s32 search_id = aki_packet_read_s32(packet); + if (search_id == -1) return; + results->page = aki_packet_read_s32(packet); + u32 size = aki_packet_read_u32(packet); + for (u32 i = 0; i < size; i++) { + struct sho_post post; + aki_packet_read_sho_post(packet, &post); + sho_post_cache_push(&client->search.cache, &post); + } + size = aki_packet_read_u32(packet); + for (u32 i = 0; i < size; i++) { + str s, unique_id; + aki_packet_read_string(packet, &s); + al_str_clone(&unique_id, &s); + al_array_push(results->results, unique_id); + } + client->callback(client->userdata, CAMU_CLIENT_RESULTS, results); + aki_packet_free(packet); +} + +void camu_client_more_results(struct camu_client *client, struct camu_search *search) +{ + struct aki_packet *packet = aki_rpc_get_packet(&client->client, TREE_CMD_SEARCH); + aki_packet_write_s32(packet, search->id); + aki_packet_write_string(packet, &search->provider); + aki_packet_write_string(packet, &search->query); + packet->userdata = search_callback; + aki_packet_pool_submit(&client->pool, packet); +} diff --git a/src/libclient/client.h b/src/libclient/client.h new file mode 100644 index 0000000..989c839 --- /dev/null +++ b/src/libclient/client.h @@ -0,0 +1,31 @@ +#pragma once + +#include <aki/rpc2.h> +#include <aki/thread.h> +#include <aki/packet_pool.h> + +#include "search.h" + +enum { + CAMU_CLIENT_CONNECTED = 0, + // Search client. + CAMU_CLIENT_RESULTS +}; + +struct camu_client { + struct aki_event_loop loop; + struct aki_rpc client; + str username; + struct aki_rpc_connection *conn; + struct camu_search_client search; + struct aki_packet_pool pool; + struct aki_thread thread; + void (*callback)(void *, u8, void *); + void *userdata; +}; + +bool camu_client_init(struct camu_client *client); +bool camu_client_login(struct camu_client *client, str *username, str *addr, s32 port, + void (*callback)(void *, u8, void *), void *userdata); +void camu_client_more_results(struct camu_client *client, struct camu_search *search); +void camu_client_close(struct camu_client *client); diff --git a/src/libclient/commands.h b/src/libclient/commands.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/src/libclient/commands.h @@ -0,0 +1 @@ +#pragma once diff --git a/src/libclient/meson.build b/src/libclient/meson.build new file mode 100644 index 0000000..a2f23b0 --- /dev/null +++ b/src/libclient/meson.build @@ -0,0 +1,3 @@ +libclient_src = ['client.c', 'resource_client.c'] +libclient_deps = [shoki] +libclient = declare_dependency(sources: libclient_src, dependencies: libclient_deps) diff --git a/src/libclient/resource_client.c b/src/libclient/resource_client.c new file mode 100644 index 0000000..1069755 --- /dev/null +++ b/src/libclient/resource_client.c @@ -0,0 +1,91 @@ +#include <al/random.h> + +#include "../tree/tree.h" + +#include "resource_client.h" + +static void connection_callback(void *userdata, struct aki_packet_stream *stream) +{ + struct camu_resource_client *client = (struct camu_resource_client *)userdata; + (void)stream; + client->connected = true; +} + +static void connection_closed_callback(void *userdata, struct aki_packet_stream *stream) +{ + struct camu_resource_client *client = (struct camu_resource_client *)userdata; + (void)stream; + client->connected = true; +} + +static void packet_callback(void *userdata, struct aki_packet_stream *stream, + struct aki_packet *packet) +{ + struct camu_resource_client *client = (struct camu_resource_client *)userdata; + (void)stream; + u16 id = aki_packet_read_u16(packet); + struct aki_buffer buffer; + aki_buffer_init(&buffer); + aki_packet_read_buffer(packet, &buffer); + client->callback(client->userdata, id, &buffer); +} + +static void packet_sent_callback(void *userdata, struct aki_packet *packet) +{ + (void)userdata; + aki_packet_free(packet); +} + +static void signal_callback(void *userdata) +{ + struct camu_resource_client *client = (struct camu_resource_client *)userdata; + u32 size; + struct camu_resource_request request; + do { + camu_queue_size(client->queue, size); + if (!size) break; + camu_queue_pop(client->queue, request); + struct aki_packet *packet = aki_packet_create(); + aki_packet_write_u16(packet, request.id); + aki_packet_write_string(packet, &request.unique_id); + aki_packet_write_u32(packet, request.index); + aki_packet_stream_send_packet(&client->client, packet); + } while (1); +} + +static aki_thread_result AKI_THREADCALL event_loop_thread(void *userdata) +{ + struct camu_resource_client *client = (struct camu_resource_client *)userdata; + aki_event_loop_run(&client->loop); + return 0; +} + +void camu_resource_client_run(struct camu_resource_client *client, + void (*callback)(void *, u16, struct aki_buffer *), void *userdata) +{ + client->callback = callback; + client->userdata = userdata; + camu_queue_init(client->queue); + aki_event_loop_init(&client->loop); + aki_signal_init(&client->signal, signal_callback, client); + aki_signal_start(&client->signal, &client->loop); + aki_packet_stream_init(&client->client, AKI_SOCKET_TCP, connection_callback, + connection_closed_callback, packet_callback, packet_sent_callback, client); + aki_packet_stream_connect(&client->client, &client->loop, al_str_c("127.0.0.1"), TREE_RESOURCE_PORT); + client->connected = false; + while (!client->connected) { + aki_event_loop_run_once(&client->loop); + } + aki_thread_create(&client->thread, event_loop_thread, client); +} + +void camu_resource_request(struct camu_resource_client *client, + str *unique_id, u32 index, u16 id) +{ + struct camu_resource_request request; + request.id = id; + al_str_clone(&request.unique_id, unique_id); + request.index = index; + camu_queue_push(client->queue, request); + aki_signal_send(&client->signal); +} diff --git a/src/libclient/resource_client.h b/src/libclient/resource_client.h new file mode 100644 index 0000000..4cc1bbf --- /dev/null +++ b/src/libclient/resource_client.h @@ -0,0 +1,29 @@ +#pragma once + +#include <aki/packet_stream.h> +#include <aki/thread.h> +#include <aki/signal.h> + +#include "../util/queue.h" + +struct camu_resource_request { + u16 id; + str unique_id; + u32 index; +}; + +struct camu_resource_client { + struct aki_event_loop loop; + struct aki_packet_stream client; + bool connected; + struct aki_thread thread; + struct aki_signal signal; + queue(struct camu_resource_request) queue; + void (*callback)(void *, u16, struct aki_buffer *); + void *userdata; +}; + +void camu_resource_client_run(struct camu_resource_client *client, + void (*callback)(void *, u16, struct aki_buffer *), void *userdata); +void camu_resource_request(struct camu_resource_client *client, + str *unique_id, u32 index, u16 id); diff --git a/src/libclient/search.c b/src/libclient/search.c new file mode 100644 index 0000000..f74f83d --- /dev/null +++ b/src/libclient/search.c @@ -0,0 +1,31 @@ +#include "search.h" + +void camu_search_client_init(struct camu_search_client *client) +{ + client->id = 0; + sho_post_cache_init(&client->cache); +} + +void camu_search_set(struct camu_search_client *client, struct camu_search *search, + str *provider, str *query) +{ + search->id = client->id++; + al_str_clone(&search->provider, provider); + al_str_clone(&search->query, query); +} + +void camu_search_free(struct camu_search *search) +{ + al_str_free(&search->provider); + al_str_free(&search->query); +} + +void camu_search_results_free(struct camu_search_results *results) +{ + str *unique_id; + al_array_foreach_ptr(results->results, i, unique_id) { + al_str_free(unique_id); + } + al_array_free(results->results); + al_free(results); +} diff --git a/src/libclient/search.h b/src/libclient/search.h new file mode 100644 index 0000000..b0d8554 --- /dev/null +++ b/src/libclient/search.h @@ -0,0 +1,28 @@ +#pragma once + +#include <al/array.h> +#include <al/str.h> + +#include "../shoki/src/post_cache.h" + +struct camu_search { + s32 id; + str provider; + str query; +}; + +struct camu_search_results { + u32 page; + array(str) results; +}; + +struct camu_search_client { + s32 id; + struct sho_post_cache cache; +}; + +void camu_search_client_init(struct camu_search_client *client); +void camu_search_set(struct camu_search_client *client, struct camu_search *search, + str *provider, str *query); +void camu_search_free(struct camu_search *search); +void camu_search_results_free(struct camu_search_results *results); |