ddat interop with dat js cable interop with cabal js ddat's frontend = dat-thang cable fe = cable-thang dillo support based on cel's dillo-dat bootstrap node xplatform support Signed-off-by: divo <418@cryspace.space>
226 lines
9.8 KiB
C
226 lines
9.8 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
#include "dat.h"
|
|
#include "sleep_verify.h"
|
|
#include "sleep_feed.h"
|
|
#include "sleep.h"
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
|
|
static int changes_seen;
|
|
static uint64_t last_change_version;
|
|
static int directory_entries_seen;
|
|
|
|
static int count_change(const sleep_metadata_entry_t *entry, uint64_t version,
|
|
void *context)
|
|
{
|
|
(void)entry;
|
|
(void)context;
|
|
changes_seen++;
|
|
last_change_version = version;
|
|
return 0;
|
|
}
|
|
|
|
static int count_directory_entry(const sleep_metadata_entry_t *entry,
|
|
const char *name, void *context)
|
|
{
|
|
(void)entry;
|
|
(void)context;
|
|
assert(!strcmp(name, "sample.bin"));
|
|
directory_entries_seen++;
|
|
return 0;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
char directory[] = "/tmp/datgpt-archive-XXXXXX";
|
|
char sync_directory[] = "/tmp/datgpt-sync-XXXXXX";
|
|
char secrets_directory[] = "/tmp/datgpt-secrets-XXXXXX";
|
|
dat_archive_t archive, reopened;
|
|
dat_archive_t sync_archive;
|
|
sleep_metadata_entry_t entry;
|
|
uint8_t *input, *output;
|
|
uint8_t parsed_key[DAT_KEY_BYTES];
|
|
char url[DAT_URL_BYTES];
|
|
char hex[65];
|
|
char legacy_url[DAT_URL_BYTES];
|
|
char link_text[DAT_LINK_BYTES];
|
|
char probe_path[256];
|
|
char secret_path[1024], discovery_hex[65];
|
|
uint8_t discovery_key[32];
|
|
struct stat secret_stat;
|
|
FILE *probe;
|
|
dat_link_t link, parsed_link;
|
|
dat_checkout_t checkout;
|
|
dat_url_t parsed_url;
|
|
dat_path_info_t path_info;
|
|
int serve_listing;
|
|
uint64_t old_version, new_version, sync_version;
|
|
sleep_feed_t remote_feed;
|
|
uint8_t remote_key[32] = {0x42}, remote_proof[] = {0x01, 0x02};
|
|
uint8_t remote_value[] = {0x61, 0x00, 0x62}, remote_value3[] = {0x63};
|
|
uint8_t *remote_read;
|
|
static const uint8_t old_text[] = "old archive value\n";
|
|
static const uint8_t new_text[] = "new archive value\n";
|
|
size_t input_len = DAT_BLOCK_BYTES * 2 + 123;
|
|
size_t output_len, i;
|
|
|
|
assert(mkdtemp(directory) != NULL);
|
|
assert(mkdtemp(secrets_directory) != NULL);
|
|
memset(&remote_feed, 0, sizeof(remote_feed));
|
|
remote_feed.remote_only = 1;
|
|
memcpy(remote_feed.keypair.pubkey, remote_key, sizeof(remote_key));
|
|
assert(sleep_feed_append_remote(&remote_feed, 0, remote_value, sizeof(remote_value),
|
|
remote_proof, sizeof(remote_proof)) == 0);
|
|
assert(sleep_feed_read(&remote_feed, 0, &remote_read, &output_len) == 0);
|
|
assert(output_len == sizeof(remote_value) && !memcmp(remote_read, remote_value, output_len));
|
|
free(remote_read);
|
|
assert(sleep_feed_append_remote(&remote_feed, 3, remote_value3, sizeof(remote_value3),
|
|
remote_proof, sizeof(remote_proof)) == 0);
|
|
assert(sleep_feed_length(&remote_feed) == 4);
|
|
assert(sleep_feed_has(&remote_feed, 2) == 0);
|
|
assert(sleep_feed_read(&remote_feed, 2, &remote_read, &output_len) != 0);
|
|
assert(sleep_feed_read(&remote_feed, 3, &remote_read, &output_len) == 0);
|
|
assert(output_len == sizeof(remote_value3) && remote_read[0] == remote_value3[0]);
|
|
free(remote_read);
|
|
assert(sleep_feed_append(&remote_feed, remote_value, sizeof(remote_value)) != 0);
|
|
assert(sleep_feed_flush(&remote_feed) != 0);
|
|
sleep_feed_close(&remote_feed);
|
|
input = malloc(input_len);
|
|
assert(input != NULL);
|
|
for (i = 0; i < input_len; i++)
|
|
input[i] = (uint8_t)((i * 31u + 7u) & 0xffu);
|
|
|
|
if (dat_archive_create(&archive, directory) != 0) {
|
|
perror("dat_archive_create");
|
|
return 1;
|
|
}
|
|
assert(dat_archive_save_secrets(&archive, secrets_directory) == 0);
|
|
assert(sleep_compute_discovery_key(archive.metadata_key, discovery_key) == 0);
|
|
assert(dat_key_to_hex(discovery_key, discovery_hex) == 0);
|
|
snprintf(secret_path, sizeof(secret_path), "%s/%.2s/%s", secrets_directory,
|
|
discovery_hex, discovery_hex + 2);
|
|
assert(stat(secret_path, &secret_stat) == 0 && secret_stat.st_size == 64);
|
|
assert(sleep_compute_discovery_key(archive.content_key, discovery_key) == 0);
|
|
assert(dat_key_to_hex(discovery_key, discovery_hex) == 0);
|
|
snprintf(secret_path, sizeof(secret_path), "%s/%.2s/%s", secrets_directory,
|
|
discovery_hex, discovery_hex + 2);
|
|
assert(stat(secret_path, &secret_stat) == 0 && secret_stat.st_size == 64);
|
|
assert(dat_archive_open_writable(&reopened, directory, secrets_directory) == 0);
|
|
dat_archive_close(&reopened);
|
|
assert(dat_key_to_url(archive.metadata_key, url) == 0);
|
|
assert(strlen(url) == 70);
|
|
assert(strncmp(url, "dat://", 6) == 0);
|
|
assert(dat_url_to_key(url, parsed_key) == 0);
|
|
assert(memcmp(parsed_key, archive.metadata_key, DAT_KEY_BYTES) == 0);
|
|
assert(dat_key_to_compact_url(archive.metadata_key, url) == 0);
|
|
assert(strlen(url) < 70);
|
|
assert(dat_url_to_key(url, parsed_key) == 0);
|
|
assert(memcmp(parsed_key, archive.metadata_key, DAT_KEY_BYTES) == 0);
|
|
assert(dat_key_to_hex(archive.metadata_key, hex) == 0);
|
|
snprintf(legacy_url, sizeof(legacy_url), "dat://%s", hex);
|
|
assert(dat_url_to_key(legacy_url, parsed_key) == 0);
|
|
assert(memcmp(parsed_key, archive.metadata_key, DAT_KEY_BYTES) == 0);
|
|
assert(dat_archive_append_directory(&archive, "/docs", 0755, 1) == 0);
|
|
assert(dat_archive_append_file(&archive, "/docs/sample.bin", input,
|
|
input_len, 0644, 2) == 0);
|
|
assert(dat_archive_append_symlink(&archive, "/latest",
|
|
"/docs/sample.bin", 3) == 0);
|
|
assert(dat_archive_append_file(&archive, "/versioned.txt", old_text,
|
|
sizeof(old_text) - 1, 0644, 4) == 0);
|
|
old_version = dat_archive_version(&archive);
|
|
assert(dat_archive_append_file(&archive, "/versioned.txt", new_text,
|
|
sizeof(new_text) - 1, 0644, 5) == 0);
|
|
new_version = dat_archive_version(&archive);
|
|
assert(new_version == old_version + 1);
|
|
assert(dat_checkout_init(&checkout, &archive, old_version) == 0);
|
|
assert(dat_checkout_find(&checkout, "/versioned.txt", &entry) == 0);
|
|
assert(dat_checkout_read(&checkout, &entry, &output, &output_len) == 0);
|
|
assert(output_len == sizeof(old_text) - 1);
|
|
assert(memcmp(output, old_text, output_len) == 0);
|
|
free(output);
|
|
assert(dat_archive_find(&archive, "/versioned.txt", &entry) == 0);
|
|
assert(dat_archive_read_file(&archive, &entry, &output, &output_len) == 0);
|
|
assert(output_len == sizeof(new_text) - 1);
|
|
assert(memcmp(output, new_text, output_len) == 0);
|
|
free(output);
|
|
changes_seen = 0;
|
|
last_change_version = 0;
|
|
assert(dat_archive_changes(&archive, old_version, new_version,
|
|
count_change, NULL) == 0);
|
|
assert(changes_seen == 1 && last_change_version == new_version);
|
|
memset(&link, 0, sizeof(link));
|
|
memcpy(link.key, archive.metadata_key, DAT_KEY_BYTES);
|
|
link.has_version = 1;
|
|
link.version = old_version;
|
|
strcpy(link.path, "versioned.txt");
|
|
assert(dat_link_format(&link, link_text, sizeof(link_text)) == 0);
|
|
assert(strstr(link_text, "+") != NULL);
|
|
assert(strlen(link_text) >= 70);
|
|
assert(dat_link_parse(link_text, &parsed_link) == 0);
|
|
assert(parsed_link.has_version && parsed_link.version == old_version);
|
|
assert(!strcmp(parsed_link.path, "versioned.txt"));
|
|
assert(!memcmp(parsed_link.key, archive.metadata_key, DAT_KEY_BYTES));
|
|
assert(dat_link_format_compact(&link, link_text, sizeof(link_text)) == 0);
|
|
assert(dat_link_parse(link_text, &parsed_link) == 0);
|
|
assert(!memcmp(parsed_link.key, archive.metadata_key, DAT_KEY_BYTES));
|
|
assert(dat_url_parse("dat://protozoa.nz/path%20name?version=7&stat=1", &parsed_url) == 0);
|
|
assert(!strcmp(parsed_url.host, "protozoa.nz"));
|
|
assert(!strcmp(parsed_url.path, "/path name"));
|
|
assert(parsed_url.has_version && parsed_url.version == 7 && parsed_url.wants_stat);
|
|
assert(dat_url_parse("dat://protozoa.nz+8/dir//", &parsed_url) == 0);
|
|
assert(parsed_url.has_version && parsed_url.version == 8 && parsed_url.force_directory_listing);
|
|
assert(dat_url_parse("dat://protozoa.nz/dir/../page", &parsed_url) == 0);
|
|
assert(!strcmp(parsed_url.path, "/page"));
|
|
assert(dat_archive_stat_at(&archive, old_version, "/docs", &path_info) == 0);
|
|
assert(path_info.exists && path_info.is_directory);
|
|
directory_entries_seen = 0;
|
|
assert(dat_archive_readdir_at(&archive, old_version, "/docs", count_directory_entry, NULL) == 0);
|
|
assert(directory_entries_seen == 1);
|
|
assert(dat_archive_resolve_at(&archive, old_version, "/docs/",
|
|
0, &path_info, &serve_listing) == 0);
|
|
assert(serve_listing);
|
|
assert(dat_archive_find(&archive, "/docs/sample.bin", &entry) == 0);
|
|
assert(entry.block_count == 3);
|
|
assert(entry.size == input_len);
|
|
assert(dat_archive_read_file(&archive, &entry, &output, &output_len) == 0);
|
|
assert(output_len == input_len);
|
|
assert(memcmp(input, output, input_len) == 0);
|
|
free(output);
|
|
dat_archive_close(&archive);
|
|
|
|
assert(dat_archive_open(&reopened, directory) == 0);
|
|
assert(dat_archive_find(&reopened, "/docs/sample.bin", &entry) == 0);
|
|
assert(dat_archive_read_file(&reopened, &entry, &output, &output_len) == 0);
|
|
assert(output_len == input_len);
|
|
assert(memcmp(input, output, input_len) == 0);
|
|
free(output);
|
|
free(input);
|
|
assert(sleep_verify_dat(reopened.dat_path) == 0);
|
|
assert(dat_archive_append_file(&reopened, "/page.html",
|
|
(const uint8_t *)"<h1>page</h1>", 13, 0644, 6) == 0);
|
|
assert(dat_archive_resolve_at(&reopened, dat_archive_version(&reopened), "/page",
|
|
0, &path_info, &serve_listing) == 0);
|
|
assert(!serve_listing && !strcmp(path_info.entry.path, "/page.html"));
|
|
assert(!strcmp(dat_content_type(path_info.entry.path), "text/html"));
|
|
dat_archive_close(&reopened);
|
|
assert(mkdtemp(sync_directory) != NULL);
|
|
assert(dat_archive_create(&sync_archive, sync_directory) == 0);
|
|
assert(snprintf(probe_path, sizeof(probe_path), "%s/mtime-probe", sync_directory) > 0);
|
|
probe = fopen(probe_path, "wb");
|
|
assert(probe != NULL);
|
|
assert(fwrite("mtime", 1, 5, probe) == 5);
|
|
assert(fclose(probe) == 0);
|
|
assert(dat_archive_sync_path(&sync_archive, sync_directory, "") == 0);
|
|
assert(dat_archive_find(&sync_archive, "mtime-probe", &entry) == 0);
|
|
assert(entry.mtime > UINT64_C(1000000000000)); /* Hyperdrive stores epoch milliseconds. */
|
|
sync_version = dat_archive_version(&sync_archive);
|
|
assert(dat_archive_sync_path(&sync_archive, sync_directory, "") == 0);
|
|
assert(dat_archive_version(&sync_archive) == sync_version); /* unchanged paths do not append */
|
|
dat_archive_close(&sync_archive);
|
|
return 0;
|
|
}
|