Allow specifying of the session account with ini: syntax

This commit is contained in:
2026-07-16 23:35:48 +10:00
parent 2f06b2cd76
commit e1991685ef
2 changed files with 244 additions and 42 deletions
+229 -39
View File
@@ -1,17 +1,40 @@
#include "dn_seshc.h" #include "dn_seshc.h"
struct DN_SHSendDMThreadContext_
{
DN_Arena arena;
DN_SHCLIArgs args;
DN_Str8 sesh_pkey_hex;
DN_Str8 msg;
};
DN_SHCLIArgs DN_SH_CLIArgsCopy(DN_SHCLIArgs const *src, DN_Arena *arena)
{
DN_SHCLIArgs result = {};
result = *src;
result.exe_path = DN_Str8FromStr8Arena(src->exe_path, arena);
result.account_secret = DN_Str8FromStr8Arena(src->account_secret, arena);
result.seed_node_url = DN_Str8FromStr8Arena(src->seed_node_url, arena);
result.display_name = DN_Str8FromStr8Arena(src->display_name, arena);
result.recipient_pkey = DN_Str8FromStr8Arena(src->recipient_pkey, arena);
return result;
}
DN_Str8 DN_SH_CLIOptionsStr8() DN_Str8 DN_SH_CLIOptionsStr8()
{ {
DN_Str8 result = DN_Str8Lit( DN_Str8 result = DN_Str8Lit(
"SESHC OPTIONS (note all options must be set to activate Seshc):\n" "SESHC OPTIONS (note all options must be set to activate Seshc):\n"
" --seshc-exe-path <path> Path to the Seshc EXE file to invoke for sending messages\n" " --seshc-exe-path <path> Path to the Seshc EXE file to invoke for sending messages\n"
" --seshc-account-secret <secret> Specify the secret of the Session account to send a message\n" " --seshc-ini-path <path> Path to the .ini file to load the secret/recipient public\n"
" as (see --help on the Seshc EXE for more info)\n" " key (only used if you are using `ini:` syntax)\n"
" --seshc-seed-node <url> URL to the Session seed node for determining the nodes to\n" " --seshc-account-secret <secret> Specify the secret of the Session account to send a message\n"
" send the message to\n" " as (see --help on the Seshc EXE for more info)\n"
" --seshc-display-name <name> Display name to send the message as\n" " --seshc-seed-node <url> URL to the Session seed node for determining the nodes to\n"
" --seshc-recipient-pkey <name> Recipient to send the message as (must be 0x05 prefixed, 0x\n" " send the message to\n"
" is optional)" " --seshc-display-name <name> Display name to send the message as\n"
" --seshc-recipient-pkey <name|ini:..> Recipient to send the message as (must be 0x05 prefixed, 0x\n"
" is optional), or alternatively `ini:` syntax (see --help on\n"
" the Seshc EXE for more info)."
); );
return result; return result;
} }
@@ -40,6 +63,18 @@ DN_SHCLIEatArgResult DN_SH_CLIEatArg(DN_SHCLIArgs *args, char const **arg_ptr, i
} }
} }
if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-ini-path"))) {
(void)DN_ArgShift(result.arg_ptr, result.arg_count);
result.eaten = true;
args->ini_path = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count));
if (DN_OS_PathInfo(args->ini_path).type != DN_OSPathInfoType_File) {
result.error_msg = DN_Str8Lit("Seshc ini path does not point to a file");
result.error_arg = args->ini_path;
args->ini_path = {};
}
}
if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-account-secret"))) { if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-account-secret"))) {
(void)DN_ArgShift(result.arg_ptr, result.arg_count); (void)DN_ArgShift(result.arg_ptr, result.arg_count);
result.eaten = true; result.eaten = true;
@@ -63,53 +98,208 @@ DN_SHCLIEatArgResult DN_SH_CLIEatArg(DN_SHCLIArgs *args, char const **arg_ptr, i
result.eaten = true; result.eaten = true;
args->recipient_pkey = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count)); args->recipient_pkey = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count));
DN_Str8 check = DN_Str8TrimHexPrefix(args->recipient_pkey); DN_Str8 check = DN_Str8TrimHexPrefix(args->recipient_pkey);
if (!DN_Str8StartsWithSensitive(check, DN_Str8Lit("05"))) { bool ini_prefixed = DN_Str8StartsWithSensitive(check, DN_Str8Lit("ini:"));
result.error_msg = DN_Str8Lit("Seshc recipient public key does not have a 05 prefix"); bool sesh_prefixed = !ini_prefixed && (DN_Str8StartsWithSensitive(check, DN_Str8Lit("05")) || DN_Str8StartsWithInsensitive(check, DN_Str8Lit("0x05")));
if (!ini_prefixed && !sesh_prefixed) {
result.error_msg = DN_Str8Lit("Seshc recipient public key does not specify a 05 prefixed public key, or, use `ini:` to specify a public key in the .ini file");
result.error_arg = args->recipient_pkey; result.error_arg = args->recipient_pkey;
args->recipient_pkey = {}; args->recipient_pkey = {};
} }
} }
} }
if (args->seed_node_url.count && args->account_secret.count && args->exe_path.count && args->display_name.count && args->recipient_pkey.count) if (args->seed_node_url.count && args->account_secret.count && args->exe_path.count && args->recipient_pkey.count)
args->valid = true; args->valid = true;
return result; return result;
} }
bool DN_SH_CLIArgsSendDMFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey_hex, char const *fmt, ...) bool DN_SH_CLIArgsSendDMBlockingFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, char const *fmt, ...)
{ {
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0); bool result = false;
if (cli_args->valid) {
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
va_list args;
va_start(args, fmt);
DN_Str8 msg = DN_Str8FromFmtVArena(&scratch.arena, fmt, args);
va_end(args);
DN_Str8 account_secret_arg = DN_Str8Lit("--account-secret");
DN_Str8 seed_node_url_arg = DN_Str8Lit("--seed-node-url");
DN_Str8 display_name_arg = DN_Str8Lit("--display-name");
DN_Str8 ini_path_arg = DN_Str8Lit("--ini-path");
DN_Str8 send_arg = DN_Str8Lit("send");
DN_Str8 cmds[16] = {};
DN_USize cmds_count = 0;
DN_LArrayAppend(cmds, &cmds_count, cli_args->exe_path);
DN_LArrayAppend(cmds, &cmds_count, account_secret_arg);
DN_LArrayAppend(cmds, &cmds_count, cli_args->account_secret);
DN_LArrayAppend(cmds, &cmds_count, seed_node_url_arg);
DN_LArrayAppend(cmds, &cmds_count, cli_args->seed_node_url);
if (cli_args->display_name.count) {
DN_LArrayAppend(cmds, &cmds_count, display_name_arg);
DN_LArrayAppend(cmds, &cmds_count, cli_args->display_name);
}
if (cli_args->ini_path.count) {
DN_LArrayAppend(cmds, &cmds_count, ini_path_arg);
DN_LArrayAppend(cmds, &cmds_count, cli_args->ini_path);
}
DN_LArrayAppend(cmds, &cmds_count, send_arg);
DN_LArrayAppend(cmds, &cmds_count, sesh_pkey);
DN_LArrayAppend(cmds, &cmds_count, msg);
DN_Str8Slice cmd_line = {};
cmd_line.data = cmds;
cmd_line.count = cmds_count;
DN_OSExecArgs exec_args = {};
exec_args.flags |= DN_OSExecFlags_SaveOutput;
DN_OSExecResult exec = DN_OS_Exec(cmd_line, &exec_args, &scratch.arena, nullptr);
result = exec.os_error_code == 0 && exec.exit_code == 0;
if (!result) {
DN_LogErrorF("Error sending message to %.*s (exit code: %d, os: %d): %.*s",
DN_Str8PrintFmt(cli_args->recipient_pkey),
exec.exit_code,
exec.os_error_code,
DN_Str8PrintFmt(exec.stderr_text));
}
DN_TCScratchEnd(&scratch);
}
return result;
}
static int DN_SH_CLIArgsSendDMDetachedFmtThreadFunc_(DN_OSThread *thread)
{
DN_SHSendDMThreadContext_ *context = DN_Cast(DN_SHSendDMThreadContext_ *) thread->user_context;
DN_SH_CLIArgsSendDMBlockingFmt(&context->args, context->sesh_pkey_hex, "%.*s", DN_Str8PrintFmt(context->msg));
DN_ArenaDeinit(&context->arena);
return 0;
}
void DN_SH_CLIArgsSendDMDetachedFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, char const *fmt, ...)
{
if (!cli_args->valid)
return;
// NOTE: Setup context
DN_Arena arena = DN_OS_ArenaFromHeapVirtual(0, 0, DN_MemFlags_Nil);
DN_SHSendDMThreadContext_ *context = DN_ArenaNewZ(&arena, DN_SHSendDMThreadContext_);
context->args = DN_SH_CLIArgsCopy(cli_args, &arena);
context->sesh_pkey_hex = DN_Str8FromStr8Arena(sesh_pkey, &arena);
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
DN_Str8 msg = DN_Str8FromFmtVArena(&scratch.arena, fmt, args); context->msg = DN_Str8FromFmtVArena(&arena, fmt, args);
va_end(args); va_end(args);
DN_Str8 cmds[] = { // NOTE: Set the arena last after all allocations
cli_args->exe_path, context->arena = arena;
DN_Str8Lit("--account-secret"),
cli_args->account_secret,
DN_Str8Lit("--seed-node-url"),
cli_args->seed_node_url,
DN_Str8Lit("--display-name"),
DN_Str8FromFmtArena(&scratch.arena, "\"%.*s\"", DN_Str8PrintFmt(cli_args->display_name)),
DN_Str8Lit("send"),
sesh_pkey_hex,
msg,
};
DN_Str8Slice cmd_line = {}; // NOTE: Setup thread to be detached
cmd_line.data = cmds; DN_OSThread thread = {};
cmd_line.count = DN_ArrayCountU(cmds); DN_OSThreadInitArgs thread_args = DN_OS_ThreadInitArgsDefault();
thread_args.flags |= DN_OSThreadFlags_Detached;
DN_OSExecArgs exec_args = {}; // NOTE: Execute and forget
exec_args.flags |= DN_OSExecFlags_SaveOutput; DN_OS_ThreadInit(&thread, DN_SH_CLIArgsSendDMDetachedFmtThreadFunc_, thread_args, context);
DN_OSExecResult exec = DN_OS_Exec(cmd_line, &exec_args, &scratch.arena, nullptr); }
DN_LogInfoF("OUT (exit code:%zu, os: %zu): %.*s", exec.exit_code, exec.os_error_code, DN_Str8PrintFmt(exec.stdout_text));
DN_LogInfoF("ERR: %.*s", DN_Str8PrintFmt(exec.stderr_text)); void DN_SH_LogBroadcastBlockingFmt(DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...)
DN_TCScratchEnd(&scratch); {
va_list args;
bool result = exec.os_error_code == 0 && exec.exit_code == 0; va_start(args, fmt);
return result; DN_SH_LogBroadcastFmtV(DN_SHLogMode_Blocking, type, cli_args, short_desc, fmt, args);
va_end(args);
}
void DN_SH_LogBroadcastDetachedFmt(DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
DN_SH_LogBroadcastFmtV(DN_SHLogMode_Detached, type, cli_args, short_desc, fmt, args);
va_end(args);
}
void DN_SH_LogBroadcastFmtV(DN_SHLogMode mode, DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, va_list args)
{
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
DN_Str8 msg = DN_Str8FromFmtVArena(&scratch.arena, fmt, args);
DN_Str8 prefix = {};
switch (type) {
case DN_LogType_Debug: prefix = DN_Str8Lit("🐞 "); break;
case DN_LogType_Info: prefix = DN_Str8Lit(""); break;
case DN_LogType_Warning: prefix = DN_Str8Lit("⚠️ "); break;
case DN_LogType_Error: prefix = DN_Str8Lit("🚨 "); break;
case DN_LogType_Count: break;
}
DN_LogF(type, "%.*s%.*s\n%.*s", DN_Str8PrintFmt(prefix), DN_Str8PrintFmt(short_desc), DN_Str8PrintFmt(msg));
DN_Date date = DN_OS_DateLocalTimeNow();
// NOTE: 12-hour conversion
DN_U8 hour12 = date.hour % 12;
if (hour12 == 0)
hour12 = 12;
char const *am_pm = date.hour < 12 ? "AM" : "PM";
// Time-of-day emoji
DN_Str8 time_emoji = {};
if (date.hour >= 5 && date.hour <= 11)
time_emoji = DN_Str8Lit("☀️");
else if (date.hour >= 12 && date.hour <= 16)
time_emoji = DN_Str8Lit("🌤️");
else if (date.hour >= 17 && date.hour <= 19)
time_emoji = DN_Str8Lit("🌅");
else if (date.hour >= 20 && date.hour <= 23)
time_emoji = DN_Str8Lit("");
else
time_emoji = DN_Str8Lit("🌑");
if (mode == DN_SHLogMode_Detached) {
DN_SH_CLIArgsSendDMDetachedFmt(cli_args,
cli_args->recipient_pkey,
"%.*s%.*s\n"
"%.*s %u-%02u-%02u %u:%02u:%02u %s\n"
"%.*s",
DN_Str8PrintFmt(prefix),
DN_Str8PrintFmt(short_desc),
DN_Str8PrintFmt(time_emoji),
date.year,
date.month,
date.day,
hour12,
date.minutes,
date.seconds,
am_pm,
DN_Str8PrintFmt(msg));
} else {
DN_Assert(mode == DN_SHLogMode_Blocking);
DN_SH_CLIArgsSendDMBlockingFmt(cli_args,
cli_args->recipient_pkey,
"%.*s %.*s\n"
"%.*s %u-%02u-%02u %u:%02u:%02u %s\n"
"%.*s",
DN_Str8PrintFmt(prefix),
DN_Str8PrintFmt(short_desc),
DN_Str8PrintFmt(time_emoji),
date.year,
date.month,
date.day,
hour12,
date.minutes,
date.seconds,
am_pm,
DN_Str8PrintFmt(msg));
}
DN_TCScratchEnd(&scratch);
} }
+15 -3
View File
@@ -10,6 +10,7 @@ struct DN_SHCLIArgs
{ {
bool valid; bool valid;
DN_Str8 exe_path; DN_Str8 exe_path;
DN_Str8 ini_path;
DN_Str8 account_secret; DN_Str8 account_secret;
DN_Str8 seed_node_url; DN_Str8 seed_node_url;
DN_Str8 display_name; DN_Str8 display_name;
@@ -25,12 +26,23 @@ struct DN_SHCLIEatArgResult
DN_USize arg_count; // Next argument count that that the caller should assume DN_USize arg_count; // Next argument count that that the caller should assume
}; };
enum DN_SHLogMode
{
DN_SHLogMode_Blocking,
DN_SHLogMode_Detached,
};
// NOTE: Seshc // NOTE: Seshc
// Overview // Overview
// Helper library that provides some useful APIs for programatically calling the Seshc CLI // Helper library that provides some useful APIs for programatically calling the Seshc CLI
// executable to send messages from your C/C++ application. // executable to send messages from your C/C++ application.
DN_Str8 DN_SH_CLIOptionsStr8 (); DN_SHCLIArgs DN_SH_CLIArgsCopy (DN_SHCLIArgs const *src, DN_Arena *arena);
DN_SHCLIEatArgResult DN_SH_CLIEatArg (DN_SHCLIArgs *args, char const **arg_ptr, int arg_count); DN_Str8 DN_SH_CLIOptionsStr8 ();
bool DN_SH_CLIArgsSendDMFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey_hex, char const *fmt, ...); DN_SHCLIEatArgResult DN_SH_CLIEatArg (DN_SHCLIArgs *args, char const **arg_ptr, int arg_count);
bool DN_SH_CLIArgsSendDMBlockingFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, char const *fmt, ...);
void DN_SH_CLIArgsSendDMDetachedFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, char const *fmt, ...);
void DN_SH_LogBroadcastFmtV (DN_SHLogMode mode, DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, va_list args);
void DN_SH_LogBroadcastBlockingFmt (DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...);
void DN_SH_LogBroadcastDetachedFmt (DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...);
#endif // #if !defined(DN_SESHC_H) #endif // #if !defined(DN_SESHC_H)