summaryrefslogtreecommitdiff
path: root/src/libclient
diff options
context:
space:
mode:
Diffstat (limited to 'src/libclient')
-rw-r--r--src/libclient/client.c98
-rw-r--r--src/libclient/client.h31
-rw-r--r--src/libclient/commands.h1
-rw-r--r--src/libclient/meson.build3
-rw-r--r--src/libclient/resource_client.c91
-rw-r--r--src/libclient/resource_client.h29
-rw-r--r--src/libclient/search.c31
-rw-r--r--src/libclient/search.h28
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);