Add concept inspection endpoints and UI upload
This commit is contained in:
parent
bed97fc22d
commit
ccfee235a9
|
|
@ -122,6 +122,13 @@ Resolve the latest ref:
|
|||
curl --unix-socket amduatd.sock http://localhost/v1/resolve/hello
|
||||
```
|
||||
|
||||
Inspect concepts:
|
||||
|
||||
```sh
|
||||
curl --unix-socket amduatd.sock http://localhost/v1/concepts
|
||||
curl --unix-socket amduatd.sock http://localhost/v1/concepts/hello
|
||||
```
|
||||
|
||||
## Current endpoints
|
||||
|
||||
- `GET /v1/meta` → `{store_id, encoding_profile_id, hash_id, api_contract_ref}`
|
||||
|
|
@ -138,6 +145,8 @@ curl --unix-socket amduatd.sock http://localhost/v1/resolve/hello
|
|||
- request: `{name, ref?}` (`name` is lowercase; `ref` publishes an initial version)
|
||||
- response: `{name, concept_ref}`
|
||||
- `POST /v1/concepts/{name}/publish` → publishes a new version `{ref}`
|
||||
- `GET /v1/concepts` → `{concepts:[{name, concept_ref}]}`
|
||||
- `GET /v1/concepts/{name}` → `{name, concept_ref, latest_ref, versions[]}`
|
||||
- `GET /v1/resolve/{name}` → `{ref}` (latest published)
|
||||
- `POST /v1/pel/run`
|
||||
- request: `{program_ref, input_refs[], params_ref?, scheme_ref?}` (`program_ref`/`input_refs`/`params_ref` accept hex refs or concept names; omit `scheme_ref` to use `dag`)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"contract":"AMDUATD/API/1","base_path":"/v1","endpoints":[{"method":"GET","path":"/v1/ui"},{"method":"GET","path":"/v1/meta"},{"method":"HEAD","path":"/v1/meta"},{"method":"GET","path":"/v1/contract"},{"method":"POST","path":"/v1/concepts"},{"method":"POST","path":"/v1/concepts/{name}/publish"},{"method":"GET","path":"/v1/resolve/{name}"},{"method":"POST","path":"/v1/artifacts"},{"method":"GET","path":"/v1/artifacts/{ref}"},{"method":"HEAD","path":"/v1/artifacts/{ref}"},{"method":"POST","path":"/v1/pel/run"},{"method":"POST","path":"/v1/pel/programs"}],"schemas":{"pel_run_request":{"type":"object","required":["program_ref","input_refs"],"properties":{"program_ref":{"type":"string","description":"hex ref or concept name"},"input_refs":{"type":"array","items":{"type":"string","description":"hex ref or concept name"}},"params_ref":{"type":"string","description":"hex ref or concept name"},"scheme_ref":{"type":"string","description":"hex ref or 'dag'"}}},"pel_run_response":{"type":"object","required":["result_ref","output_refs","status"],"properties":{"result_ref":{"type":"string","description":"hex ref"},"trace_ref":{"type":"string","description":"hex ref"},"output_refs":{"type":"array","items":{"type":"string","description":"hex ref"}},"status":{"type":"string"}}},"pel_program_author_request":{"type":"object","required":["nodes","roots"],"properties":{"nodes":{"type":"array"},"roots":{"type":"array"}}}}}
|
||||
{"contract":"AMDUATD/API/1","base_path":"/v1","endpoints":[{"method":"GET","path":"/v1/ui"},{"method":"GET","path":"/v1/meta"},{"method":"HEAD","path":"/v1/meta"},{"method":"GET","path":"/v1/contract"},{"method":"POST","path":"/v1/concepts"},{"method":"GET","path":"/v1/concepts"},{"method":"GET","path":"/v1/concepts/{name}"},{"method":"POST","path":"/v1/concepts/{name}/publish"},{"method":"GET","path":"/v1/resolve/{name}"},{"method":"POST","path":"/v1/artifacts"},{"method":"GET","path":"/v1/artifacts/{ref}"},{"method":"HEAD","path":"/v1/artifacts/{ref}"},{"method":"POST","path":"/v1/pel/run"},{"method":"POST","path":"/v1/pel/programs"}],"schemas":{"pel_run_request":{"type":"object","required":["program_ref","input_refs"],"properties":{"program_ref":{"type":"string","description":"hex ref or concept name"},"input_refs":{"type":"array","items":{"type":"string","description":"hex ref or concept name"}},"params_ref":{"type":"string","description":"hex ref or concept name"},"scheme_ref":{"type":"string","description":"hex ref or 'dag'"}}},"pel_run_response":{"type":"object","required":["result_ref","output_refs","status"],"properties":{"result_ref":{"type":"string","description":"hex ref"},"trace_ref":{"type":"string","description":"hex ref"},"output_refs":{"type":"array","items":{"type":"string","description":"hex ref"}},"status":{"type":"string"}}},"pel_program_author_request":{"type":"object","required":["nodes","roots"],"properties":{"nodes":{"type":"array"},"roots":{"type":"array"}}},"concept_create_request":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"ref":{"type":"string","description":"hex ref"}}}}}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"registry":"AMDUATD/API","contract":"AMDUATD/API/1","handle":"amduat.api.amduatd.contract.v1@1","media_type":"application/json","status":"active","bytes_sha256":"e7459c83f8473e4665ae30c3ead65385bf666618500e8d782b0b0450ae55a3e0","notes":"Seeded into the ASL store at amduatd startup; ref is advertised via /v1/meta."}
|
||||
{"registry":"AMDUATD/API","contract":"AMDUATD/API/1","handle":"amduat.api.amduatd.contract.v1@1","media_type":"application/json","status":"active","bytes_sha256":"3c8ef7489b0499ebb6e8025981c6f43962568d554d63d6994d75e43812e17feb","notes":"Seeded into the ASL store at amduatd startup; ref is advertised via /v1/meta."}
|
||||
|
|
|
|||
349
src/amduatd.c
349
src/amduatd.c
|
|
@ -35,6 +35,27 @@
|
|||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct amduatd_strbuf {
|
||||
char *data;
|
||||
size_t len;
|
||||
size_t cap;
|
||||
} amduatd_strbuf_t;
|
||||
|
||||
static bool amduatd_http_send_json(int fd,
|
||||
int code,
|
||||
const char *reason,
|
||||
const char *json,
|
||||
bool head_only);
|
||||
|
||||
static bool amduatd_send_json_error(int fd,
|
||||
int code,
|
||||
const char *reason,
|
||||
const char *msg);
|
||||
|
||||
static void amduatd_strbuf_free(amduatd_strbuf_t *b);
|
||||
static bool amduatd_strbuf_append_cstr(amduatd_strbuf_t *b, const char *s);
|
||||
static bool amduatd_strbuf_append_char(amduatd_strbuf_t *b, char c);
|
||||
|
||||
static const char *const AMDUATD_DEFAULT_ROOT = ".amduat-asl";
|
||||
static const char *const AMDUATD_DEFAULT_SOCK = "amduatd.sock";
|
||||
static const char *const AMDUATD_EDGES_FILE = ".amduatd.edges";
|
||||
|
|
@ -115,6 +136,8 @@ static const char k_amduatd_contract_v1_json[] =
|
|||
"{\"method\":\"HEAD\",\"path\":\"/v1/meta\"},"
|
||||
"{\"method\":\"GET\",\"path\":\"/v1/contract\"},"
|
||||
"{\"method\":\"POST\",\"path\":\"/v1/concepts\"},"
|
||||
"{\"method\":\"GET\",\"path\":\"/v1/concepts\"},"
|
||||
"{\"method\":\"GET\",\"path\":\"/v1/concepts/{name}\"},"
|
||||
"{\"method\":\"POST\",\"path\":\"/v1/concepts/{name}/publish\"},"
|
||||
"{\"method\":\"GET\",\"path\":\"/v1/resolve/{name}\"},"
|
||||
"{\"method\":\"POST\",\"path\":\"/v1/artifacts\"},"
|
||||
|
|
@ -228,6 +251,12 @@ static const char k_amduatd_ui_html[] =
|
|||
" <div class=\"row\" style=\"margin-top:10px;\">\n"
|
||||
" <button id=\"btnConceptCreate\" type=\"button\">Create concept</button>\n"
|
||||
" <button id=\"btnConceptPublish\" type=\"button\">Publish program_ref</button>\n"
|
||||
" <button id=\"btnConceptLoad\" type=\"button\">Load</button>\n"
|
||||
" </div>\n"
|
||||
" <div style=\"margin:10px 0 8px;\" class=\"muted\">Upload bytes (sets program_ref)</div>\n"
|
||||
" <div class=\"row\">\n"
|
||||
" <input id=\"uploadFile\" type=\"file\" />\n"
|
||||
" <button id=\"btnUpload\" type=\"button\">Upload</button>\n"
|
||||
" </div>\n"
|
||||
" <div class=\"row\" style=\"margin-top:12px;\">\n"
|
||||
" <button id=\"btnRun\" type=\"button\">Run program</button>\n"
|
||||
|
|
@ -307,6 +336,36 @@ static const char k_amduatd_ui_html[] =
|
|||
" }\n"
|
||||
" });\n"
|
||||
"\n"
|
||||
" el('btnConceptLoad').addEventListener('click', async () => {\n"
|
||||
" try {\n"
|
||||
" const name = el('conceptName').value.trim();\n"
|
||||
" const resp = await fetch(`/v1/concepts/${encodeURIComponent(name)}`);\n"
|
||||
" out(await resp.text());\n"
|
||||
" } catch (e) {\n"
|
||||
" out(String(e));\n"
|
||||
" }\n"
|
||||
" });\n"
|
||||
"\n"
|
||||
" el('btnUpload').addEventListener('click', async () => {\n"
|
||||
" try {\n"
|
||||
" const file = el('uploadFile').files && el('uploadFile').files[0];\n"
|
||||
" if (!file) { out('no file selected'); return; }\n"
|
||||
" const resp = await fetch('/v1/artifacts', {\n"
|
||||
" method: 'POST',\n"
|
||||
" headers: { 'Content-Type': 'application/octet-stream' },\n"
|
||||
" body: file\n"
|
||||
" });\n"
|
||||
" const text = await resp.text();\n"
|
||||
" out(text);\n"
|
||||
" if (resp.ok) {\n"
|
||||
" const j = JSON.parse(text);\n"
|
||||
" if (j && j.ref) el('programRef').value = j.ref;\n"
|
||||
" }\n"
|
||||
" } catch (e) {\n"
|
||||
" out(String(e));\n"
|
||||
" }\n"
|
||||
" });\n"
|
||||
"\n"
|
||||
" el('btnRun').addEventListener('click', async () => {\n"
|
||||
" try {\n"
|
||||
" const program_ref = el('programRef').value.trim();\n"
|
||||
|
|
@ -873,6 +932,281 @@ static bool amduatd_concepts_resolve_latest(amduat_asl_store_t *store,
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool amduatd_parse_name_artifact(amduat_artifact_t artifact,
|
||||
char *out,
|
||||
size_t cap) {
|
||||
const uint8_t *bytes;
|
||||
size_t len;
|
||||
const char *prefix = "AMDUATD/NAME/1";
|
||||
size_t prefix_len;
|
||||
size_t i;
|
||||
size_t name_len;
|
||||
|
||||
if (out != NULL && cap != 0) {
|
||||
out[0] = '\0';
|
||||
}
|
||||
if (out == NULL || cap == 0) {
|
||||
return false;
|
||||
}
|
||||
if (artifact.bytes.len != 0 && artifact.bytes.data == NULL) {
|
||||
return false;
|
||||
}
|
||||
bytes = artifact.bytes.data;
|
||||
len = artifact.bytes.len;
|
||||
prefix_len = strlen(prefix);
|
||||
if (len < prefix_len + 1u) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(bytes, prefix, prefix_len) != 0 || bytes[prefix_len] != 0) {
|
||||
return false;
|
||||
}
|
||||
for (i = prefix_len + 1u; i < len; ++i) {
|
||||
if (bytes[i] == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
name_len = len - (prefix_len + 1u);
|
||||
if (name_len == 0 || name_len >= cap) {
|
||||
return false;
|
||||
}
|
||||
memcpy(out, bytes + prefix_len + 1u, name_len);
|
||||
out[name_len] = '\0';
|
||||
return amduatd_name_valid(out);
|
||||
}
|
||||
|
||||
static bool amduatd_handle_get_concepts(int fd,
|
||||
amduat_asl_store_t *store,
|
||||
const amduatd_concepts_t *concepts) {
|
||||
amduatd_strbuf_t b;
|
||||
bool first = true;
|
||||
size_t i;
|
||||
|
||||
if (store == NULL || concepts == NULL) {
|
||||
return amduatd_send_json_error(fd, 500, "Internal Server Error",
|
||||
"internal error");
|
||||
}
|
||||
memset(&b, 0, sizeof(b));
|
||||
if (!amduatd_strbuf_append_cstr(&b, "{\"concepts\":[")) {
|
||||
amduatd_strbuf_free(&b);
|
||||
return amduatd_send_json_error(fd, 500, "Internal Server Error", "oom");
|
||||
}
|
||||
|
||||
for (i = 0; i < concepts->edge_refs.len; ++i) {
|
||||
amduat_reference_t edge_ref = concepts->edge_refs.refs[i];
|
||||
amduat_artifact_t artifact;
|
||||
amduat_tgk_edge_body_t edge;
|
||||
amduat_asl_store_error_t err;
|
||||
char name[128];
|
||||
char *concept_hex = NULL;
|
||||
|
||||
memset(&artifact, 0, sizeof(artifact));
|
||||
err = amduat_asl_store_get(store, edge_ref, &artifact);
|
||||
if (err != AMDUAT_ASL_STORE_OK) {
|
||||
continue;
|
||||
}
|
||||
if (!artifact.has_type_tag ||
|
||||
artifact.type_tag.tag_id != AMDUAT_TYPE_TAG_TGK1_EDGE_V1) {
|
||||
amduat_asl_artifact_free(&artifact);
|
||||
continue;
|
||||
}
|
||||
memset(&edge, 0, sizeof(edge));
|
||||
if (!amduat_enc_tgk1_edge_decode_v1(artifact.bytes, &edge)) {
|
||||
amduat_asl_artifact_free(&artifact);
|
||||
continue;
|
||||
}
|
||||
if (!(edge.from_len == 1 && edge.to_len == 1 &&
|
||||
amduat_reference_eq(edge.payload, concepts->rel_aliases_ref))) {
|
||||
amduat_enc_tgk1_edge_free(&edge);
|
||||
amduat_asl_artifact_free(&artifact);
|
||||
continue;
|
||||
}
|
||||
amduat_asl_artifact_free(&artifact);
|
||||
|
||||
memset(&artifact, 0, sizeof(artifact));
|
||||
err = amduat_asl_store_get(store, edge.from[0], &artifact);
|
||||
if (err != AMDUAT_ASL_STORE_OK ||
|
||||
!amduatd_parse_name_artifact(artifact, name, sizeof(name))) {
|
||||
amduat_enc_tgk1_edge_free(&edge);
|
||||
amduat_asl_artifact_free(&artifact);
|
||||
continue;
|
||||
}
|
||||
amduat_asl_artifact_free(&artifact);
|
||||
|
||||
if (!amduat_asl_ref_encode_hex(edge.to[0], &concept_hex)) {
|
||||
amduat_enc_tgk1_edge_free(&edge);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!first) {
|
||||
(void)amduatd_strbuf_append_char(&b, ',');
|
||||
}
|
||||
first = false;
|
||||
|
||||
(void)amduatd_strbuf_append_cstr(&b, "{\"name\":\"");
|
||||
(void)amduatd_strbuf_append_cstr(&b, name);
|
||||
(void)amduatd_strbuf_append_cstr(&b, "\",\"concept_ref\":\"");
|
||||
(void)amduatd_strbuf_append_cstr(&b, concept_hex);
|
||||
(void)amduatd_strbuf_append_cstr(&b, "\"}");
|
||||
|
||||
free(concept_hex);
|
||||
amduat_enc_tgk1_edge_free(&edge);
|
||||
}
|
||||
|
||||
if (!amduatd_strbuf_append_cstr(&b, "]}\n")) {
|
||||
amduatd_strbuf_free(&b);
|
||||
return amduatd_send_json_error(fd, 500, "Internal Server Error", "oom");
|
||||
}
|
||||
{
|
||||
bool ok = amduatd_http_send_json(fd, 200, "OK", b.data, false);
|
||||
amduatd_strbuf_free(&b);
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
static bool amduatd_handle_get_concept(int fd,
|
||||
amduat_asl_store_t *store,
|
||||
const amduat_asl_store_fs_config_t *cfg,
|
||||
const amduatd_concepts_t *concepts,
|
||||
const char *name) {
|
||||
amduat_reference_t concept_ref;
|
||||
amduat_reference_t latest_ref;
|
||||
amduatd_strbuf_t b;
|
||||
char *concept_hex = NULL;
|
||||
char *latest_hex = NULL;
|
||||
bool have_latest = false;
|
||||
size_t i;
|
||||
size_t version_count = 0;
|
||||
|
||||
memset(&concept_ref, 0, sizeof(concept_ref));
|
||||
memset(&latest_ref, 0, sizeof(latest_ref));
|
||||
memset(&b, 0, sizeof(b));
|
||||
|
||||
if (store == NULL || cfg == NULL || concepts == NULL || name == NULL) {
|
||||
return amduatd_send_json_error(fd, 500, "Internal Server Error",
|
||||
"internal error");
|
||||
}
|
||||
if (!amduatd_name_valid(name)) {
|
||||
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid name");
|
||||
}
|
||||
if (!amduatd_concepts_lookup_alias(store, cfg, concepts, name, &concept_ref)) {
|
||||
return amduatd_send_json_error(fd, 404, "Not Found", "unknown concept");
|
||||
}
|
||||
if (amduatd_concepts_resolve_latest(store, concepts, concept_ref,
|
||||
&latest_ref)) {
|
||||
have_latest = true;
|
||||
}
|
||||
|
||||
if (!amduat_asl_ref_encode_hex(concept_ref, &concept_hex)) {
|
||||
amduat_reference_free(&concept_ref);
|
||||
amduat_reference_free(&latest_ref);
|
||||
return amduatd_send_json_error(fd, 500, "Internal Server Error",
|
||||
"encode error");
|
||||
}
|
||||
if (have_latest) {
|
||||
if (!amduat_asl_ref_encode_hex(latest_ref, &latest_hex)) {
|
||||
free(concept_hex);
|
||||
amduat_reference_free(&concept_ref);
|
||||
amduat_reference_free(&latest_ref);
|
||||
return amduatd_send_json_error(fd, 500, "Internal Server Error",
|
||||
"encode error");
|
||||
}
|
||||
}
|
||||
|
||||
if (!amduatd_strbuf_append_cstr(&b, "{")) {
|
||||
free(concept_hex);
|
||||
free(latest_hex);
|
||||
amduat_reference_free(&concept_ref);
|
||||
amduat_reference_free(&latest_ref);
|
||||
return amduatd_send_json_error(fd, 500, "Internal Server Error", "oom");
|
||||
}
|
||||
(void)amduatd_strbuf_append_cstr(&b, "\"name\":\"");
|
||||
(void)amduatd_strbuf_append_cstr(&b, name);
|
||||
(void)amduatd_strbuf_append_cstr(&b, "\",\"concept_ref\":\"");
|
||||
(void)amduatd_strbuf_append_cstr(&b, concept_hex);
|
||||
(void)amduatd_strbuf_append_cstr(&b, "\",\"latest_ref\":");
|
||||
if (latest_hex != NULL) {
|
||||
(void)amduatd_strbuf_append_cstr(&b, "\"");
|
||||
(void)amduatd_strbuf_append_cstr(&b, latest_hex);
|
||||
(void)amduatd_strbuf_append_cstr(&b, "\"");
|
||||
} else {
|
||||
(void)amduatd_strbuf_append_cstr(&b, "null");
|
||||
}
|
||||
(void)amduatd_strbuf_append_cstr(&b, ",\"versions\":[");
|
||||
|
||||
for (i = 0; i < concepts->edge_refs.len; ++i) {
|
||||
amduat_reference_t edge_ref = concepts->edge_refs.refs[i];
|
||||
amduat_artifact_t artifact;
|
||||
amduat_tgk_edge_body_t edge;
|
||||
amduat_asl_store_error_t err;
|
||||
char *edge_hex = NULL;
|
||||
char *ref_hex = NULL;
|
||||
|
||||
memset(&artifact, 0, sizeof(artifact));
|
||||
err = amduat_asl_store_get(store, edge_ref, &artifact);
|
||||
if (err != AMDUAT_ASL_STORE_OK) {
|
||||
continue;
|
||||
}
|
||||
if (!artifact.has_type_tag ||
|
||||
artifact.type_tag.tag_id != AMDUAT_TYPE_TAG_TGK1_EDGE_V1) {
|
||||
amduat_asl_artifact_free(&artifact);
|
||||
continue;
|
||||
}
|
||||
memset(&edge, 0, sizeof(edge));
|
||||
if (!amduat_enc_tgk1_edge_decode_v1(artifact.bytes, &edge)) {
|
||||
amduat_asl_artifact_free(&artifact);
|
||||
continue;
|
||||
}
|
||||
amduat_asl_artifact_free(&artifact);
|
||||
|
||||
if (!(edge.from_len == 1 && edge.to_len == 1 &&
|
||||
amduat_reference_eq(edge.payload, concepts->rel_materializes_ref) &&
|
||||
amduat_reference_eq(edge.from[0], concept_ref))) {
|
||||
amduat_enc_tgk1_edge_free(&edge);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!amduat_asl_ref_encode_hex(edge_ref, &edge_hex) ||
|
||||
!amduat_asl_ref_encode_hex(edge.to[0], &ref_hex)) {
|
||||
free(edge_hex);
|
||||
free(ref_hex);
|
||||
amduat_enc_tgk1_edge_free(&edge);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (version_count != 0) {
|
||||
(void)amduatd_strbuf_append_char(&b, ',');
|
||||
}
|
||||
version_count++;
|
||||
|
||||
(void)amduatd_strbuf_append_cstr(&b, "{\"edge_ref\":\"");
|
||||
(void)amduatd_strbuf_append_cstr(&b, edge_hex);
|
||||
(void)amduatd_strbuf_append_cstr(&b, "\",\"ref\":\"");
|
||||
(void)amduatd_strbuf_append_cstr(&b, ref_hex);
|
||||
(void)amduatd_strbuf_append_cstr(&b, "\"}");
|
||||
|
||||
free(edge_hex);
|
||||
free(ref_hex);
|
||||
amduat_enc_tgk1_edge_free(&edge);
|
||||
|
||||
if (version_count >= 64u) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(void)amduatd_strbuf_append_cstr(&b, "]}\n");
|
||||
|
||||
free(concept_hex);
|
||||
free(latest_hex);
|
||||
amduat_reference_free(&concept_ref);
|
||||
amduat_reference_free(&latest_ref);
|
||||
|
||||
{
|
||||
bool ok = amduatd_http_send_json(fd, 200, "OK", b.data, false);
|
||||
amduatd_strbuf_free(&b);
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
static bool amduatd_read_exact(int fd, uint8_t *buf, size_t len) {
|
||||
size_t off = 0;
|
||||
while (off < len) {
|
||||
|
|
@ -1182,11 +1516,6 @@ static const char *amduatd_query_param(const char *path,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *data;
|
||||
size_t len;
|
||||
size_t cap;
|
||||
} amduatd_strbuf_t;
|
||||
|
||||
static void amduatd_strbuf_free(amduatd_strbuf_t *b) {
|
||||
if (b == NULL) {
|
||||
|
|
@ -3623,6 +3952,16 @@ static bool amduatd_handle_conn(int fd,
|
|||
if (strcmp(req.method, "POST") == 0 && strcmp(no_query, "/v1/concepts") == 0) {
|
||||
return amduatd_handle_post_concepts(fd, store, cfg, concepts, &req);
|
||||
}
|
||||
if (strcmp(req.method, "GET") == 0 && strcmp(no_query, "/v1/concepts") == 0) {
|
||||
return amduatd_handle_get_concepts(fd, store, concepts);
|
||||
}
|
||||
if (strcmp(req.method, "GET") == 0 && strncmp(no_query, "/v1/concepts/", 13) == 0) {
|
||||
const char *name = no_query + 13;
|
||||
if (name[0] == '\0') {
|
||||
return amduatd_send_json_error(fd, 400, "Bad Request", "missing name");
|
||||
}
|
||||
return amduatd_handle_get_concept(fd, store, cfg, concepts, name);
|
||||
}
|
||||
if (strcmp(req.method, "POST") == 0 &&
|
||||
strncmp(no_query, "/v1/concepts/", 13) == 0 &&
|
||||
strstr(no_query, "/publish") != NULL) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue