267 lines
9.9 KiB
C
267 lines
9.9 KiB
C
#include "tui.h"
|
|
#include "state.h"
|
|
#include "net.h"
|
|
|
|
#include "publish.h"
|
|
|
|
#include "../resources/nostr_core_lib/cjson/cJSON.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static int relays_publish_kind10002(cJSON *event_obj) {
|
|
cJSON *tags;
|
|
cJSON *content;
|
|
|
|
if (!event_obj) {
|
|
return -1;
|
|
}
|
|
|
|
tags = cJSON_GetObjectItemCaseSensitive(event_obj, "tags");
|
|
content = cJSON_GetObjectItemCaseSensitive(event_obj, "content");
|
|
|
|
return publish_signed_event_with_report("Relay list",
|
|
10002,
|
|
(cJSON_IsString(content) && content->valuestring) ? content->valuestring : "",
|
|
tags,
|
|
8000);
|
|
}
|
|
|
|
static void relays_print_nip11_summary(const char *nip11_json) {
|
|
cJSON *doc;
|
|
cJSON *name;
|
|
cJSON *description;
|
|
cJSON *software;
|
|
cJSON *version;
|
|
cJSON *pubkey;
|
|
cJSON *contact;
|
|
cJSON *supported_nips;
|
|
cJSON *limitation;
|
|
|
|
if (!nip11_json || nip11_json[0] == '\0') {
|
|
tui_print("NIP-11: (empty response)");
|
|
return;
|
|
}
|
|
|
|
doc = cJSON_Parse(nip11_json);
|
|
if (!doc || !cJSON_IsObject(doc)) {
|
|
tui_print("NIP-11 (raw): %s", nip11_json);
|
|
cJSON_Delete(doc);
|
|
return;
|
|
}
|
|
|
|
name = cJSON_GetObjectItemCaseSensitive(doc, "name");
|
|
description = cJSON_GetObjectItemCaseSensitive(doc, "description");
|
|
software = cJSON_GetObjectItemCaseSensitive(doc, "software");
|
|
version = cJSON_GetObjectItemCaseSensitive(doc, "version");
|
|
pubkey = cJSON_GetObjectItemCaseSensitive(doc, "pubkey");
|
|
contact = cJSON_GetObjectItemCaseSensitive(doc, "contact");
|
|
supported_nips = cJSON_GetObjectItemCaseSensitive(doc, "supported_nips");
|
|
limitation = cJSON_GetObjectItemCaseSensitive(doc, "limitation");
|
|
|
|
tui_print("NIP-11 relay profile:");
|
|
tui_print(" Name: %s", (cJSON_IsString(name) && name->valuestring) ? name->valuestring : "(n/a)");
|
|
tui_print(" Description: %s", (cJSON_IsString(description) && description->valuestring) ? description->valuestring : "(n/a)");
|
|
tui_print(" Software: %s", (cJSON_IsString(software) && software->valuestring) ? software->valuestring : "(n/a)");
|
|
tui_print(" Version: %s", (cJSON_IsString(version) && version->valuestring) ? version->valuestring : "(n/a)");
|
|
tui_print(" Contact: %s", (cJSON_IsString(contact) && contact->valuestring) ? contact->valuestring : "(n/a)");
|
|
tui_print(" Pubkey: %s", (cJSON_IsString(pubkey) && pubkey->valuestring) ? pubkey->valuestring : "(n/a)");
|
|
|
|
if (cJSON_IsArray(supported_nips)) {
|
|
char *nips_json = cJSON_PrintUnformatted(supported_nips);
|
|
if (nips_json) {
|
|
tui_print(" Supported NIPs: %s", nips_json);
|
|
free(nips_json);
|
|
}
|
|
}
|
|
|
|
if (cJSON_IsObject(limitation)) {
|
|
cJSON *max_subscriptions = cJSON_GetObjectItemCaseSensitive(limitation, "max_subscriptions");
|
|
cJSON *max_message_length = cJSON_GetObjectItemCaseSensitive(limitation, "max_message_length");
|
|
cJSON *max_limit = cJSON_GetObjectItemCaseSensitive(limitation, "max_limit");
|
|
|
|
tui_print(" Limits:");
|
|
if (cJSON_IsNumber(max_subscriptions)) {
|
|
tui_print(" max_subscriptions: %d", max_subscriptions->valueint);
|
|
}
|
|
if (cJSON_IsNumber(max_message_length)) {
|
|
tui_print(" max_message_length: %d", max_message_length->valueint);
|
|
}
|
|
if (cJSON_IsNumber(max_limit)) {
|
|
tui_print(" max_limit: %d", max_limit->valueint);
|
|
}
|
|
}
|
|
|
|
cJSON_Delete(doc);
|
|
}
|
|
|
|
void menu_relays(void) {
|
|
cJSON *working = NULL;
|
|
cJSON *tags = NULL;
|
|
char input[512];
|
|
|
|
working = g_state.kind10002_json ? cJSON_Parse(g_state.kind10002_json) : NULL;
|
|
if (!working) {
|
|
working = cJSON_CreateObject();
|
|
cJSON_AddNumberToObject(working, "kind", 10002);
|
|
cJSON_AddStringToObject(working, "content", "");
|
|
cJSON_AddItemToObject(working, "tags", cJSON_CreateArray());
|
|
}
|
|
|
|
tags = cJSON_GetObjectItemCaseSensitive(working, "tags");
|
|
if (!cJSON_IsArray(tags)) {
|
|
cJSON_DeleteItemFromObjectCaseSensitive(working, "tags");
|
|
cJSON_AddItemToObject(working, "tags", cJSON_CreateArray());
|
|
tags = cJSON_GetObjectItemCaseSensitive(working, "tags");
|
|
}
|
|
|
|
while (1) {
|
|
int i;
|
|
int n;
|
|
|
|
tui_clear_screen();
|
|
tui_print("RELAYS\n");
|
|
|
|
n = cJSON_GetArraySize(tags);
|
|
for (i = 0; i < n; i++) {
|
|
cJSON *tag = cJSON_GetArrayItem(tags, i);
|
|
cJSON *t0 = cJSON_GetArrayItem(tag, 0);
|
|
cJSON *t1 = cJSON_GetArrayItem(tag, 1);
|
|
cJSON *t2 = cJSON_GetArrayItem(tag, 2);
|
|
const char *rw = "read write";
|
|
|
|
if (!cJSON_IsArray(tag) || !cJSON_IsString(t0) || !t0->valuestring || strcmp(t0->valuestring, "r") != 0) {
|
|
continue;
|
|
}
|
|
|
|
if (cJSON_IsString(t2) && t2->valuestring) {
|
|
rw = t2->valuestring;
|
|
}
|
|
|
|
tui_print("[%2d] %-30s %s", i + 1, (cJSON_IsString(t1) && t1->valuestring) ? t1->valuestring : "", rw);
|
|
}
|
|
|
|
tui_print("\n\n");
|
|
tui_print("^_A^:dd relay");
|
|
tui_print("^_D^:elete relay");
|
|
tui_print("^_M^:odify relay");
|
|
tui_print("^_P^:ost changes and exit.");
|
|
tui_print("E^_x^:it without saving");
|
|
|
|
tui_get_line(">", input, (int)sizeof(input));
|
|
|
|
if (input[0] == 'a' || input[0] == 'A') {
|
|
char relay_url[256];
|
|
char yn[32];
|
|
char read_yn[32];
|
|
char write_yn[32];
|
|
char *nip11 = NULL;
|
|
|
|
tui_print("\n\nADD RELAY\n");
|
|
tui_get_line("Relay URL >", relay_url, (int)sizeof(relay_url));
|
|
if (relay_url[0] == '\0') {
|
|
continue;
|
|
}
|
|
|
|
tui_print("Gathering relay data ...");
|
|
if (nt_fetch_nip11(relay_url, &nip11) == 0 && nip11) {
|
|
relays_print_nip11_summary(nip11);
|
|
free(nip11);
|
|
} else {
|
|
tui_print("NIP-11 fetch failed.");
|
|
}
|
|
|
|
tui_get_line("Add relay [y/n] >", yn, (int)sizeof(yn));
|
|
if (yn[0] == 'y' || yn[0] == 'Y') {
|
|
cJSON *tag = cJSON_CreateArray();
|
|
cJSON_AddItemToArray(tag, cJSON_CreateString("r"));
|
|
cJSON_AddItemToArray(tag, cJSON_CreateString(relay_url));
|
|
|
|
tui_get_line("Read from relay [y/n] >", read_yn, (int)sizeof(read_yn));
|
|
tui_get_line("Write to relay [y/n] >", write_yn, (int)sizeof(write_yn));
|
|
|
|
if ((read_yn[0] == 'n' || read_yn[0] == 'N') && (write_yn[0] == 'y' || write_yn[0] == 'Y')) {
|
|
cJSON_AddItemToArray(tag, cJSON_CreateString("write"));
|
|
} else if ((read_yn[0] == 'y' || read_yn[0] == 'Y') && (write_yn[0] == 'n' || write_yn[0] == 'N')) {
|
|
cJSON_AddItemToArray(tag, cJSON_CreateString("read"));
|
|
}
|
|
cJSON_AddItemToArray(tags, tag);
|
|
}
|
|
} else if (input[0] == 'd' || input[0] == 'D') {
|
|
char numbuf[32];
|
|
char yn[32];
|
|
int idx;
|
|
cJSON *tag;
|
|
cJSON *url;
|
|
|
|
tui_get_line("relay to delete >", numbuf, (int)sizeof(numbuf));
|
|
idx = atoi(numbuf) - 1;
|
|
if (idx < 0 || idx >= cJSON_GetArraySize(tags)) {
|
|
continue;
|
|
}
|
|
|
|
tag = cJSON_GetArrayItem(tags, idx);
|
|
url = cJSON_GetArrayItem(tag, 1);
|
|
tui_get_line("Delete selected relay [y/n] >", yn, (int)sizeof(yn));
|
|
if (yn[0] == 'y' || yn[0] == 'Y') {
|
|
cJSON_DeleteItemFromArray(tags, idx);
|
|
if (cJSON_IsString(url) && url->valuestring) {
|
|
tui_print("Deleted %s", url->valuestring);
|
|
}
|
|
}
|
|
} else if (input[0] == 'm' || input[0] == 'M') {
|
|
char numbuf[32];
|
|
char read_yn[32];
|
|
char write_yn[32];
|
|
int idx;
|
|
cJSON *old_tag;
|
|
cJSON *url;
|
|
cJSON *new_tag;
|
|
|
|
tui_get_line("# relay to modify >", numbuf, (int)sizeof(numbuf));
|
|
idx = atoi(numbuf) - 1;
|
|
if (idx < 0 || idx >= cJSON_GetArraySize(tags)) {
|
|
continue;
|
|
}
|
|
|
|
old_tag = cJSON_GetArrayItem(tags, idx);
|
|
url = cJSON_GetArrayItem(old_tag, 1);
|
|
if (!cJSON_IsString(url) || !url->valuestring || url->valuestring[0] == '\0') {
|
|
continue;
|
|
}
|
|
|
|
new_tag = cJSON_CreateArray();
|
|
cJSON_AddItemToArray(new_tag, cJSON_CreateString("r"));
|
|
cJSON_AddItemToArray(new_tag, cJSON_CreateString(url->valuestring));
|
|
|
|
tui_get_line("Read from relay [y/n]?", read_yn, (int)sizeof(read_yn));
|
|
tui_get_line("Write to relay [y/n]?", write_yn, (int)sizeof(write_yn));
|
|
|
|
if ((read_yn[0] == 'n' || read_yn[0] == 'N') && (write_yn[0] == 'y' || write_yn[0] == 'Y')) {
|
|
cJSON_AddItemToArray(new_tag, cJSON_CreateString("write"));
|
|
} else if ((read_yn[0] == 'y' || read_yn[0] == 'Y') && (write_yn[0] == 'n' || write_yn[0] == 'N')) {
|
|
cJSON_AddItemToArray(new_tag, cJSON_CreateString("read"));
|
|
}
|
|
|
|
cJSON_ReplaceItemInArray(tags, idx, new_tag);
|
|
} else if (input[0] == 'p' || input[0] == 'P') {
|
|
int posted = relays_publish_kind10002(working);
|
|
char *new_json = cJSON_PrintUnformatted(working);
|
|
if (new_json) {
|
|
free(g_state.kind10002_json);
|
|
g_state.kind10002_json = new_json;
|
|
state_parse_relay_list();
|
|
}
|
|
if (posted < 0) {
|
|
tui_print("Relay list publish failed.");
|
|
}
|
|
tui_get_line(">", input, (int)sizeof(input));
|
|
break;
|
|
} else if (input[0] == 'x' || input[0] == 'X' || input[0] == 'q' || input[0] == 'Q') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
cJSON_Delete(working);
|
|
}
|