646 lines
20 KiB
C
646 lines
20 KiB
C
|
|
#include "amduatd_fed_push_plan.h"
|
||
|
|
|
||
|
|
#include "amduat/asl/log_store.h"
|
||
|
|
#include "amduat/asl/artifact_io.h"
|
||
|
|
#include "amduat/asl/ref_text.h"
|
||
|
|
#include "amduat/asl/store.h"
|
||
|
|
#include "amduat/enc/fer1_receipt.h"
|
||
|
|
#include "amduat/enc/tgk1_edge.h"
|
||
|
|
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
char *data;
|
||
|
|
size_t len;
|
||
|
|
size_t cap;
|
||
|
|
} amduatd_fed_push_plan_strbuf_t;
|
||
|
|
|
||
|
|
static void amduatd_fed_push_plan_strbuf_free(
|
||
|
|
amduatd_fed_push_plan_strbuf_t *b) {
|
||
|
|
if (b == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
free(b->data);
|
||
|
|
b->data = NULL;
|
||
|
|
b->len = 0;
|
||
|
|
b->cap = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool amduatd_fed_push_plan_strbuf_reserve(
|
||
|
|
amduatd_fed_push_plan_strbuf_t *b,
|
||
|
|
size_t extra) {
|
||
|
|
size_t need;
|
||
|
|
size_t next_cap;
|
||
|
|
char *next;
|
||
|
|
|
||
|
|
if (b == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (extra > (SIZE_MAX - b->len)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
need = b->len + extra;
|
||
|
|
if (need <= b->cap) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
next_cap = b->cap != 0 ? b->cap : 256u;
|
||
|
|
while (next_cap < need) {
|
||
|
|
if (next_cap > (SIZE_MAX / 2u)) {
|
||
|
|
next_cap = need;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
next_cap *= 2u;
|
||
|
|
}
|
||
|
|
next = (char *)realloc(b->data, next_cap);
|
||
|
|
if (next == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
b->data = next;
|
||
|
|
b->cap = next_cap;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool amduatd_fed_push_plan_strbuf_append(
|
||
|
|
amduatd_fed_push_plan_strbuf_t *b,
|
||
|
|
const char *s,
|
||
|
|
size_t n) {
|
||
|
|
if (b == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (n == 0u) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
if (s == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_reserve(b, n + 1u)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
memcpy(b->data + b->len, s, n);
|
||
|
|
b->len += n;
|
||
|
|
b->data[b->len] = '\0';
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool amduatd_fed_push_plan_strbuf_append_cstr(
|
||
|
|
amduatd_fed_push_plan_strbuf_t *b,
|
||
|
|
const char *s) {
|
||
|
|
return amduatd_fed_push_plan_strbuf_append(
|
||
|
|
b, s != NULL ? s : "", s != NULL ? strlen(s) : 0u);
|
||
|
|
}
|
||
|
|
|
||
|
|
static const char *amduatd_fed_push_plan_record_type_name(
|
||
|
|
amduat_fed_record_type_t type) {
|
||
|
|
switch (type) {
|
||
|
|
case AMDUAT_FED_REC_ARTIFACT:
|
||
|
|
return "artifact";
|
||
|
|
case AMDUAT_FED_REC_PER:
|
||
|
|
return "per";
|
||
|
|
case AMDUAT_FED_REC_TGK_EDGE:
|
||
|
|
return "tgk_edge";
|
||
|
|
case AMDUAT_FED_REC_TOMBSTONE:
|
||
|
|
return "tombstone";
|
||
|
|
default:
|
||
|
|
return "unknown";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void amduatd_fed_push_plan_candidate_init(
|
||
|
|
amduatd_fed_push_cursor_candidate_t *candidate) {
|
||
|
|
if (candidate == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
memset(candidate, 0, sizeof(*candidate));
|
||
|
|
candidate->ref = amduat_reference(0u, amduat_octets(NULL, 0u));
|
||
|
|
}
|
||
|
|
|
||
|
|
void amduatd_fed_push_plan_candidate_free(
|
||
|
|
amduatd_fed_push_cursor_candidate_t *candidate) {
|
||
|
|
if (candidate == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (candidate->has_ref) {
|
||
|
|
amduat_reference_free(&candidate->ref);
|
||
|
|
}
|
||
|
|
memset(candidate, 0, sizeof(*candidate));
|
||
|
|
}
|
||
|
|
|
||
|
|
bool amduatd_fed_push_plan_next_cursor_candidate(
|
||
|
|
const amduatd_fed_cursor_record_t *cursor,
|
||
|
|
const amduat_fed_record_t *records,
|
||
|
|
size_t record_count,
|
||
|
|
amduatd_fed_push_cursor_candidate_t *out_candidate) {
|
||
|
|
if (out_candidate == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
amduatd_fed_push_plan_candidate_init(out_candidate);
|
||
|
|
|
||
|
|
if (record_count > 0u && records != NULL) {
|
||
|
|
const amduat_fed_record_t *last = &records[record_count - 1u];
|
||
|
|
out_candidate->has_logseq = true;
|
||
|
|
out_candidate->logseq = last->logseq;
|
||
|
|
out_candidate->has_ref = true;
|
||
|
|
if (!amduat_reference_clone(last->id.ref, &out_candidate->ref)) {
|
||
|
|
amduatd_fed_push_plan_candidate_free(out_candidate);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
(void)cursor;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
amduatd_fed_push_plan_status_t amduatd_fed_push_plan_check(
|
||
|
|
const amduatd_fed_cfg_t *cfg,
|
||
|
|
const amduat_asl_store_t *store) {
|
||
|
|
if (cfg == NULL || store == NULL) {
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
if (!cfg->enabled) {
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_DISABLED;
|
||
|
|
}
|
||
|
|
if (store->ops.log_scan == NULL || store->ops.current_state == NULL) {
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_UNSUPPORTED;
|
||
|
|
}
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void amduatd_fed_push_plan_records_free(amduat_fed_record_t *records,
|
||
|
|
size_t record_count) {
|
||
|
|
size_t i;
|
||
|
|
if (records == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
for (i = 0; i < record_count; ++i) {
|
||
|
|
amduat_reference_free(&records[i].id.ref);
|
||
|
|
}
|
||
|
|
free(records);
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool amduatd_fed_push_entry_record_type(
|
||
|
|
amduat_asl_store_t *store,
|
||
|
|
const amduat_asl_log_entry_t *entry,
|
||
|
|
amduat_fed_record_type_t *out_type) {
|
||
|
|
amduat_fed_record_type_t rec_type = AMDUAT_FED_REC_ARTIFACT;
|
||
|
|
if (store == NULL || entry == NULL || out_type == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (entry->kind == AMDUATD_FED_LOG_KIND_ARTIFACT) {
|
||
|
|
amduat_artifact_t artifact;
|
||
|
|
amduat_asl_store_error_t store_err;
|
||
|
|
memset(&artifact, 0, sizeof(artifact));
|
||
|
|
store_err = amduat_asl_store_get(store, entry->payload_ref, &artifact);
|
||
|
|
if (store_err == AMDUAT_ASL_STORE_OK && artifact.has_type_tag) {
|
||
|
|
if (artifact.type_tag.tag_id == AMDUAT_TYPE_TAG_TGK1_EDGE_V1) {
|
||
|
|
rec_type = AMDUAT_FED_REC_TGK_EDGE;
|
||
|
|
} else if (artifact.type_tag.tag_id == AMDUAT_TYPE_TAG_FER1_RECEIPT_1) {
|
||
|
|
rec_type = AMDUAT_FED_REC_PER;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (store_err == AMDUAT_ASL_STORE_OK) {
|
||
|
|
amduat_asl_artifact_free(&artifact);
|
||
|
|
}
|
||
|
|
} else if (entry->kind == AMDUATD_FED_LOG_KIND_TOMBSTONE) {
|
||
|
|
rec_type = AMDUAT_FED_REC_TOMBSTONE;
|
||
|
|
} else {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
*out_type = rec_type;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void amduatd_fed_push_plan_scan_init(amduatd_fed_push_plan_scan_t *scan) {
|
||
|
|
if (scan == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
memset(scan, 0, sizeof(*scan));
|
||
|
|
amduatd_fed_cursor_record_init(&scan->cursor);
|
||
|
|
scan->cursor_ref = amduat_reference(0u, amduat_octets(NULL, 0u));
|
||
|
|
}
|
||
|
|
|
||
|
|
void amduatd_fed_push_plan_scan_free(amduatd_fed_push_plan_scan_t *scan) {
|
||
|
|
if (scan == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (scan->cursor_present) {
|
||
|
|
amduatd_fed_cursor_record_free(&scan->cursor);
|
||
|
|
amduat_reference_free(&scan->cursor_ref);
|
||
|
|
}
|
||
|
|
amduatd_fed_push_plan_records_free(scan->records, scan->record_count);
|
||
|
|
memset(scan, 0, sizeof(*scan));
|
||
|
|
}
|
||
|
|
|
||
|
|
amduatd_fed_push_plan_status_t amduatd_fed_push_plan_scan(
|
||
|
|
amduat_asl_store_t *store,
|
||
|
|
amduat_asl_pointer_store_t *pointer_store,
|
||
|
|
const amduatd_space_t *effective_space,
|
||
|
|
const char *peer_key,
|
||
|
|
uint64_t limit,
|
||
|
|
const char *root_path,
|
||
|
|
amduatd_fed_push_plan_scan_t *out_scan) {
|
||
|
|
amduat_asl_log_store_t log_store;
|
||
|
|
amduat_asl_log_entry_t *entries = NULL;
|
||
|
|
size_t entry_count = 0u;
|
||
|
|
uint64_t next_offset = 0u;
|
||
|
|
bool end = false;
|
||
|
|
amduat_octets_t log_name = amduat_octets(NULL, 0u);
|
||
|
|
uint64_t from_logseq = 0u;
|
||
|
|
|
||
|
|
if (store == NULL || pointer_store == NULL || peer_key == NULL ||
|
||
|
|
root_path == NULL || out_scan == NULL) {
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
amduatd_fed_push_plan_scan_init(out_scan);
|
||
|
|
|
||
|
|
{
|
||
|
|
amduatd_fed_cursor_status_t cursor_status;
|
||
|
|
cursor_status = amduatd_fed_push_cursor_get(store,
|
||
|
|
pointer_store,
|
||
|
|
effective_space,
|
||
|
|
peer_key,
|
||
|
|
&out_scan->cursor,
|
||
|
|
&out_scan->cursor_ref);
|
||
|
|
if (cursor_status == AMDUATD_FED_CURSOR_ERR_NOT_FOUND) {
|
||
|
|
out_scan->cursor_present = false;
|
||
|
|
} else if (cursor_status == AMDUATD_FED_CURSOR_OK) {
|
||
|
|
out_scan->cursor_present = true;
|
||
|
|
if (out_scan->cursor.has_logseq) {
|
||
|
|
if (out_scan->cursor.last_logseq == UINT64_MAX) {
|
||
|
|
amduatd_fed_push_plan_scan_free(out_scan);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
from_logseq = out_scan->cursor.last_logseq + 1u;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
amduatd_fed_push_plan_scan_free(out_scan);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!amduat_asl_log_store_init(&log_store, root_path, store,
|
||
|
|
pointer_store)) {
|
||
|
|
amduatd_fed_push_plan_scan_free(out_scan);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
if (!amduatd_space_scope_name(effective_space, "fed/records", &log_name)) {
|
||
|
|
amduatd_fed_push_plan_scan_free(out_scan);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
amduat_asl_store_error_t read_err =
|
||
|
|
amduat_asl_log_read(&log_store,
|
||
|
|
(const char *)log_name.data,
|
||
|
|
from_logseq,
|
||
|
|
(size_t)limit,
|
||
|
|
&entries,
|
||
|
|
&entry_count,
|
||
|
|
&next_offset,
|
||
|
|
&end);
|
||
|
|
amduat_octets_free(&log_name);
|
||
|
|
if (read_err != AMDUAT_ASL_STORE_OK) {
|
||
|
|
amduatd_fed_push_plan_scan_free(out_scan);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
(void)next_offset;
|
||
|
|
(void)end;
|
||
|
|
|
||
|
|
if (entry_count != 0u) {
|
||
|
|
out_scan->records =
|
||
|
|
(amduat_fed_record_t *)calloc(entry_count, sizeof(*out_scan->records));
|
||
|
|
if (out_scan->records == NULL) {
|
||
|
|
amduat_asl_log_entries_free(entries, entry_count);
|
||
|
|
amduatd_fed_push_plan_scan_free(out_scan);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_OOM;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
size_t i;
|
||
|
|
for (i = 0; i < entry_count; ++i) {
|
||
|
|
const amduat_asl_log_entry_t *entry = &entries[i];
|
||
|
|
amduat_fed_record_type_t rec_type = AMDUAT_FED_REC_ARTIFACT;
|
||
|
|
uint64_t logseq;
|
||
|
|
|
||
|
|
if (entry->payload_ref.digest.data == NULL ||
|
||
|
|
entry->payload_ref.digest.len == 0u) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (from_logseq > UINT64_MAX - (uint64_t)i) {
|
||
|
|
amduat_asl_log_entries_free(entries, entry_count);
|
||
|
|
amduatd_fed_push_plan_scan_free(out_scan);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
logseq = from_logseq + (uint64_t)i;
|
||
|
|
if (!amduatd_fed_push_entry_record_type(store, entry, &rec_type)) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
memset(&out_scan->records[out_scan->record_count], 0,
|
||
|
|
sizeof(out_scan->records[out_scan->record_count]));
|
||
|
|
out_scan->records[out_scan->record_count].id.type = rec_type;
|
||
|
|
out_scan->records[out_scan->record_count].logseq = logseq;
|
||
|
|
if (!amduat_reference_clone(entry->payload_ref,
|
||
|
|
&out_scan->records[out_scan->record_count]
|
||
|
|
.id.ref)) {
|
||
|
|
amduat_asl_log_entries_free(entries, entry_count);
|
||
|
|
amduatd_fed_push_plan_scan_free(out_scan);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_OOM;
|
||
|
|
}
|
||
|
|
out_scan->record_count++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
amduat_asl_log_entries_free(entries, entry_count);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
amduatd_fed_push_plan_status_t amduatd_fed_push_plan_json(
|
||
|
|
const amduatd_fed_push_plan_input_t *input,
|
||
|
|
char **out_json) {
|
||
|
|
amduatd_fed_push_plan_strbuf_t b;
|
||
|
|
size_t i;
|
||
|
|
const amduat_fed_record_t *first = NULL;
|
||
|
|
const amduat_fed_record_t *last = NULL;
|
||
|
|
amduatd_fed_push_cursor_candidate_t candidate;
|
||
|
|
char *ref_hex = NULL;
|
||
|
|
char *cursor_ref_hex = NULL;
|
||
|
|
char tmp[64];
|
||
|
|
|
||
|
|
if (out_json != NULL) {
|
||
|
|
*out_json = NULL;
|
||
|
|
}
|
||
|
|
if (input == NULL || out_json == NULL || input->peer_key == NULL) {
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
if (input->record_count > 0u && input->records == NULL) {
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
if (input->cursor_present && input->cursor == NULL) {
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_INVALID;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (input->record_count > 0u && input->records != NULL) {
|
||
|
|
first = &input->records[0];
|
||
|
|
last = &input->records[input->record_count - 1u];
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_next_cursor_candidate(
|
||
|
|
input->cursor_present ? input->cursor : NULL,
|
||
|
|
input->records,
|
||
|
|
input->record_count,
|
||
|
|
&candidate)) {
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_OOM;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (input->cursor_present &&
|
||
|
|
input->cursor_ref != NULL &&
|
||
|
|
input->cursor_ref->digest.data != NULL) {
|
||
|
|
if (!amduat_asl_ref_encode_hex(*input->cursor_ref, &cursor_ref_hex)) {
|
||
|
|
amduatd_fed_push_plan_candidate_free(&candidate);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_OOM;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
memset(&b, 0, sizeof(b));
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "{")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"peer\":\"") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, input->peer_key) ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\",")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
|
||
|
|
snprintf(tmp, sizeof(tmp), "%u", (unsigned int)input->domain_id);
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"domain_id\":") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, tmp) ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, ",")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"effective_space\":{")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (input->effective_space != NULL &&
|
||
|
|
input->effective_space->enabled &&
|
||
|
|
input->effective_space->space_id.data != NULL) {
|
||
|
|
const char *space_id = (const char *)input->effective_space->space_id.data;
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"mode\":\"scoped\",") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"space_id\":\"") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, space_id) ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(
|
||
|
|
&b, "\"mode\":\"unscoped\",") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"space_id\":null")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "},")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"cursor\":{")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"present\":") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b,
|
||
|
|
input->cursor_present ? "true"
|
||
|
|
: "false")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, ",\"last_logseq\":")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (input->cursor_present && input->cursor != NULL &&
|
||
|
|
input->cursor->has_logseq) {
|
||
|
|
snprintf(tmp, sizeof(tmp), "%llu",
|
||
|
|
(unsigned long long)input->cursor->last_logseq);
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, tmp)) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "null")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, ",\"ref\":")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (cursor_ref_hex != NULL) {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, cursor_ref_hex) ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "null")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "},")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"scan\":{")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
snprintf(tmp, sizeof(tmp), "%zu", input->record_count);
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"record_count\":") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, tmp)) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, ",\"first_logseq\":")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (first != NULL) {
|
||
|
|
snprintf(tmp, sizeof(tmp), "%llu", (unsigned long long)first->logseq);
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, tmp)) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "null")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, ",\"last_logseq\":")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (last != NULL) {
|
||
|
|
snprintf(tmp, sizeof(tmp), "%llu", (unsigned long long)last->logseq);
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, tmp)) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "null")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "},")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"records\":[")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
for (i = 0; i < input->record_count; ++i) {
|
||
|
|
const amduat_fed_record_t *rec = &input->records[i];
|
||
|
|
const char *type_name = amduatd_fed_push_plan_record_type_name(rec->id.type);
|
||
|
|
if (i > 0) {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, ",")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduat_asl_ref_encode_hex(rec->id.ref, &ref_hex)) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "{\"logseq\":")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
snprintf(tmp, sizeof(tmp), "%llu", (unsigned long long)rec->logseq);
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, tmp) ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, ",\"record_type\":\"") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, type_name) ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\",\"ref\":\"") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, ref_hex) ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"}")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
free(ref_hex);
|
||
|
|
ref_hex = NULL;
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "],")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b,
|
||
|
|
"\"required_artifacts\":[")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
{
|
||
|
|
bool first_artifact = true;
|
||
|
|
for (i = 0; i < input->record_count; ++i) {
|
||
|
|
const amduat_fed_record_t *rec = &input->records[i];
|
||
|
|
if (rec->id.type == AMDUAT_FED_REC_TOMBSTONE) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (!amduat_asl_ref_encode_hex(rec->id.ref, &ref_hex)) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (!first_artifact) {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, ",")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, ref_hex) ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
first_artifact = false;
|
||
|
|
free(ref_hex);
|
||
|
|
ref_hex = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "],")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(
|
||
|
|
&b, "\"next_cursor_candidate\":{")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"last_logseq\":")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (candidate.has_logseq) {
|
||
|
|
snprintf(tmp, sizeof(tmp), "%llu", (unsigned long long)candidate.logseq);
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, tmp)) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "null")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, ",\"ref\":")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (candidate.has_ref) {
|
||
|
|
if (!amduat_asl_ref_encode_hex(candidate.ref, &ref_hex)) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"") ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, ref_hex) ||
|
||
|
|
!amduatd_fed_push_plan_strbuf_append_cstr(&b, "\"")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
free(ref_hex);
|
||
|
|
ref_hex = NULL;
|
||
|
|
} else {
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "null")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!amduatd_fed_push_plan_strbuf_append_cstr(&b, "}}\n")) {
|
||
|
|
goto plan_oom;
|
||
|
|
}
|
||
|
|
|
||
|
|
amduatd_fed_push_plan_candidate_free(&candidate);
|
||
|
|
free(cursor_ref_hex);
|
||
|
|
*out_json = b.data;
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_OK;
|
||
|
|
|
||
|
|
plan_oom:
|
||
|
|
free(ref_hex);
|
||
|
|
amduatd_fed_push_plan_candidate_free(&candidate);
|
||
|
|
free(cursor_ref_hex);
|
||
|
|
amduatd_fed_push_plan_strbuf_free(&b);
|
||
|
|
return AMDUATD_FED_PUSH_PLAN_ERR_OOM;
|
||
|
|
}
|