diff --git a/Single-Header/dn_single_header.cpp b/Single-Header/dn_single_header.cpp index 970d166..ca1022d 100644 --- a/Single-Header/dn_single_header.cpp +++ b/Single-Header/dn_single_header.cpp @@ -1,4 +1,4 @@ -// Generated by the DN single header generator 2026-07-15 09:59:54 +// Generated by the DN single header generator 2026-07-15 17:58:16 // DN: Single header generator commented out => #if defined(_CLANGD) // #define DN_WITH_TESTS 1 diff --git a/Single-Header/dn_single_header.h b/Single-Header/dn_single_header.h index 1e598d8..c0117a9 100644 --- a/Single-Header/dn_single_header.h +++ b/Single-Header/dn_single_header.h @@ -1,4 +1,4 @@ -// Generated by the DN single header generator 2026-07-15 09:59:54 +// Generated by the DN single header generator 2026-07-15 17:58:16 #if !defined(DN_H) #define DN_H @@ -614,6 +614,7 @@ #define DN_Min(a, b) (((a) < (b)) ? (a) : (b)) #define DN_Clamp(val, lo, hi) DN_Max(DN_Min(val, hi), lo) #define DN_Squared(val) ((val) * (val)) +#define DN_ArgShift(ptr, size) ((size) ? ((size)--, *(ptr)++) : 0) #define DN_Swap(a, b) \ do { \ diff --git a/Source/Extra/dn_seshc.cpp b/Source/Extra/dn_seshc.cpp new file mode 100644 index 0000000..3a9313e --- /dev/null +++ b/Source/Extra/dn_seshc.cpp @@ -0,0 +1,115 @@ +#include "dn_seshc.h" + +DN_Str8 DN_SH_CLIOptionsStr8() +{ + DN_Str8 result = DN_Str8Lit( +"SESHC OPTIONS (note all options must be set to activate Seshc):\n" +" --seshc-exe-path Path to the Seshc EXE file to invoke for sending messages\n" +" --seshc-account-secret Specify the secret of the Session account to send a message\n" +" as (see --help on the Seshc EXE for more info)\n" +" --seshc-seed-node URL to the Session seed node for determining the nodes to\n" +" send the message to\n" +" --seshc-display-name Display name to send the message as\n" +" --seshc-recipient-pkey Recipient to send the message as (must be 0x05 prefixed, 0x\n" +" is optional)" + ); + return result; +} + +DN_SHCLIEatArgResult DN_SH_CLIEatArg(DN_SHCLIArgs *args, char const **arg_ptr, int arg_count) +{ + DN_SHCLIEatArgResult result = {}; + result.arg_ptr = arg_ptr; + result.arg_count = arg_count; + + DN_Str8 arg = {}; + if (arg_count) + arg = DN_Str8FromCStr8(*result.arg_ptr); + + // NOTE: Try handling the argument if we recognise it + { + if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-exe-path"))) { + (void)DN_ArgShift(result.arg_ptr, result.arg_count); + result.eaten = true; + args->exe_path = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count)); + + if (DN_OS_PathInfo(args->exe_path).type != DN_OSPathInfoType_File) { + result.error_msg = DN_Str8Lit("Seshc executable path does not point to a file"); + result.error_arg = args->exe_path; + args->exe_path = {}; + } + } + + if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-account-secret"))) { + (void)DN_ArgShift(result.arg_ptr, result.arg_count); + result.eaten = true; + args->account_secret = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count)); + } + + if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-seed-node"))) { + (void)DN_ArgShift(result.arg_ptr, result.arg_count); + result.eaten = true; + args->seed_node_url = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count)); + } + + if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-display-name"))) { + (void)DN_ArgShift(result.arg_ptr, result.arg_count); + result.eaten = true; + args->display_name = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count)); + } + + if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-recipient-pkey"))) { + (void)DN_ArgShift(result.arg_ptr, result.arg_count); + result.eaten = true; + args->recipient_pkey = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count)); + + DN_Str8 check = DN_Str8TrimHexPrefix(args->recipient_pkey); + if (!DN_Str8StartsWithSensitive(check, DN_Str8Lit("05"))) { + result.error_msg = DN_Str8Lit("Seshc recipient public key does not have a 05 prefix"); + result.error_arg = 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) + args->valid = true; + return result; +} + +bool DN_SH_CLIArgsSendDMFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey_hex, char const *fmt, ...) +{ + 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 cmds[] = { + cli_args->exe_path, + 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 = {}; + cmd_line.data = cmds; + cmd_line.count = DN_ArrayCountU(cmds); + + DN_OSExecArgs exec_args = {}; + exec_args.flags |= DN_OSExecFlags_SaveOutput; + 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)); + DN_TCScratchEnd(&scratch); + + bool result = exec.os_error_code == 0 && exec.exit_code == 0; + return result; +} diff --git a/Source/Extra/dn_seshc.h b/Source/Extra/dn_seshc.h new file mode 100644 index 0000000..1001b82 --- /dev/null +++ b/Source/Extra/dn_seshc.h @@ -0,0 +1,36 @@ +#if !defined(DN_SESHC_H) +#define DN_SESHC_H + +#if defined(_CLANGD) + #define DN_WITH_OS 1 + #include "../dn.h" +#endif + +struct DN_SHCLIArgs +{ + bool valid; + DN_Str8 exe_path; + DN_Str8 account_secret; + DN_Str8 seed_node_url; + DN_Str8 display_name; + DN_Str8 recipient_pkey; +}; + +struct DN_SHCLIEatArgResult +{ + bool eaten; + DN_Str8 error_msg; // Parsing error message. String is immutably stored in the data-segment w/ program lifetime. + DN_Str8 error_arg; // Argument that caused the parsing error + char const **arg_ptr; // Next argument pointer that that the caller should proceed from + DN_USize arg_count; // Next argument count that that the caller should assume +}; + +// NOTE: Seshc +// Overview +// Helper library that provides some useful APIs for programatically calling the Seshc CLI +// executable to send messages from your C/C++ application. +DN_Str8 DN_SH_CLIOptionsStr8 (); +DN_SHCLIEatArgResult DN_SH_CLIEatArg (DN_SHCLIArgs *args, char const **arg_ptr, int arg_count); +bool DN_SH_CLIArgsSendDMFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey_hex, char const *fmt, ...); + +#endif // #if !defined(DN_SESHC_H) diff --git a/Source/dn.h b/Source/dn.h index 7bdf9f2..b15e345 100644 --- a/Source/dn.h +++ b/Source/dn.h @@ -612,6 +612,7 @@ #define DN_Min(a, b) (((a) < (b)) ? (a) : (b)) #define DN_Clamp(val, lo, hi) DN_Max(DN_Min(val, hi), lo) #define DN_Squared(val) ((val) * (val)) +#define DN_ArgShift(ptr, size) ((size) ? ((size)--, *(ptr)++) : 0) #define DN_Swap(a, b) \ do { \