ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
runtime.h File Reference

Go to the source code of this file.

Data Structures

struct  options_edit_t
struct  options_patch_t
struct  options_patch_result_t
struct  options_snapshot_t

Macros

#define OPTIONS_REVISION_ANY   UINT64_MAX
#define OPTIONS_PATCH_MAX_EDITS   32

Enumerations

enum  options_value_type_t { OPTIONS_VALUE_INT , OPTIONS_VALUE_BOOL , OPTIONS_VALUE_DOUBLE , OPTIONS_VALUE_STRING }
enum  options_operation_t { OPTIONS_ASSIGN , OPTIONS_TOGGLE , OPTIONS_ADD , OPTIONS_CYCLE }
enum  options_origin_t { OPTIONS_ORIGIN_LOCAL , OPTIONS_ORIGIN_REMOTE , OPTIONS_ORIGIN_CONFIG }

Functions

asciichat_error_t options_apply_patch (const options_patch_t *patch, options_patch_result_t *result)
asciichat_error_t options_prepare_patch (const options_t *current, const options_patch_t *patch, options_t *candidate, bool remote_only)
asciichat_error_t options_read_snapshot (options_snapshot_t *snapshot)
uint64_t options_revision (void)
asciichat_error_t options_toggle (const char *name)
asciichat_error_t options_adjust (const char *name, double amount)
asciichat_error_t options_cycle (const char *name, int count)
bool options_remote_render_field (const char *name)
asciichat_error_t options_prepare_json (const options_t *current, const char *json, size_t length, options_t *candidate, bool remote_only)
asciichat_error_t options_apply_json (const char *json, size_t length, uint64_t expected_revision, options_origin_t origin, options_patch_result_t *result)
char * options_values_json (const options_t *values, bool remote_only)

Macro Definition Documentation

◆ OPTIONS_PATCH_MAX_EDITS

#define OPTIONS_PATCH_MAX_EDITS   32

◆ OPTIONS_REVISION_ANY

#define OPTIONS_REVISION_ANY   UINT64_MAX

Definition at line 23 of file options/runtime.h.

Referenced by options_apply_patch(), options_prepare_json(), and patch_options().

Enumeration Type Documentation

◆ options_operation_t

Enumerator
OPTIONS_ASSIGN 
OPTIONS_TOGGLE 
OPTIONS_ADD 
OPTIONS_CYCLE 

Definition at line 8 of file options/runtime.h.

◆ options_origin_t

Enumerator
OPTIONS_ORIGIN_LOCAL 
OPTIONS_ORIGIN_REMOTE 
OPTIONS_ORIGIN_CONFIG 

Definition at line 9 of file options/runtime.h.

◆ options_value_type_t

Runtime edits are applied to the latest snapshot under the writer mutex.

Enumerator
OPTIONS_VALUE_INT 
OPTIONS_VALUE_BOOL 
OPTIONS_VALUE_DOUBLE 
OPTIONS_VALUE_STRING 

Definition at line 7 of file options/runtime.h.

Function Documentation

◆ options_adjust()

asciichat_error_t options_adjust ( const char * name,
double amount )

Definition at line 914 of file rcu.c.

914 {
915 return apply_one(
916 (options_edit_t){.name = name, .type = OPTIONS_VALUE_DOUBLE, .operation = OPTIONS_ADD, .value.number = amount});
917}

References OPTIONS_ADD, and OPTIONS_VALUE_DOUBLE.

Referenced by ui_session_key().

◆ options_apply_json()

asciichat_error_t options_apply_json ( const char * json,
size_t length,
uint64_t expected_revision,
options_origin_t origin,
options_patch_result_t * result )

Definition at line 1000 of file rcu.c.

1001 {
1002 yyjson_doc *doc = NULL;
1004 size_t count = 0;
1005 asciichat_error_t error = parse_json_edits(json, length, &doc, edits, &count);
1006 options_patch_t patch = {.edits = edits, .count = count, .expected_revision = expected_revision, .origin = origin};
1007 if (error == ASCIICHAT_OK)
1008 error = options_apply_patch(&patch, result);
1009 yyjson_doc_free(doc);
1010 return error;
1011}
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
#define OPTIONS_PATCH_MAX_EDITS
asciichat_error_t options_apply_patch(const options_patch_t *patch, options_patch_result_t *result)
Definition rcu.c:837

References ASCIICHAT_OK, options_apply_patch(), and OPTIONS_PATCH_MAX_EDITS.

Referenced by patch_options().

◆ options_apply_patch()

asciichat_error_t options_apply_patch ( const options_patch_t * patch,
options_patch_result_t * result )

No observer callbacks or network I/O run under the writer mutex. A rejected patch publishes nothing.

Definition at line 837 of file rcu.c.

837 {
838 if (!patch || !patch->edits || !patch->count || patch->count > OPTIONS_PATCH_MAX_EDITS)
839 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid options patch");
840 if (!lifecycle_is_initialized(&g_options_lifecycle))
841 return SET_ERRNO(ERROR_INVALID_STATE, "Options are not initialized");
842 mutex_lock(&g_options_write_mutex);
843 if (result)
844 *result = (options_patch_result_t){.revision = g_revision};
845 if (patch->expected_revision != OPTIONS_REVISION_ANY && patch->expected_revision != g_revision) {
846 mutex_unlock(&g_options_write_mutex);
847 return SET_ERRNO(ERROR_INVALID_STATE, "Options changed; refresh and retry");
848 }
849 options_t *current = atomic_ptr_load(&g_options);
850 options_t *candidate = SAFE_MALLOC(sizeof(*candidate), options_t *);
851 asciichat_error_t error = options_prepare_patch(current, patch, candidate, false);
852 if (error == ASCIICHAT_OK && memcmp(current, candidate, sizeof(*current))) {
853 atomic_ptr_store(&g_options, candidate);
854 deferred_free_add(current);
855 ++g_revision;
856 g_origin = patch->origin;
857 if (result)
858 *result = (options_patch_result_t){.revision = g_revision, .changed = true};
859 } else
860 SAFE_FREE(candidate);
861 mutex_unlock(&g_options_write_mutex);
862 return error;
863}
#define SET_ERRNO(code,...)
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_MALLOC(size, cast)
Definition common.h:265
@ ERROR_INVALID_STATE
@ ERROR_INVALID_PARAM
struct options_state options_t
Immutable, RCU-published snapshot of the application's runtime configuration.
#define OPTIONS_REVISION_ANY
asciichat_error_t options_prepare_patch(const options_t *current, const options_patch_t *patch, options_t *candidate, bool remote_only)
Definition rcu.c:799
const options_edit_t * edits
uint64_t expected_revision
options_origin_t origin

References ASCIICHAT_OK, options_patch_t::count, options_patch_t::edits, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, options_patch_t::expected_revision, OPTIONS_PATCH_MAX_EDITS, options_prepare_patch(), OPTIONS_REVISION_ANY, options_patch_t::origin, SAFE_FREE, SAFE_MALLOC, and SET_ERRNO.

Referenced by options_apply_json().

◆ options_cycle()

asciichat_error_t options_cycle ( const char * name,
int count )

Definition at line 918 of file rcu.c.

918 {
919 return apply_one(
920 (options_edit_t){.name = name, .type = OPTIONS_VALUE_INT, .operation = OPTIONS_CYCLE, .value.integer = count});
921}

References OPTIONS_CYCLE, and OPTIONS_VALUE_INT.

Referenced by ui_session_key().

◆ options_prepare_json()

asciichat_error_t options_prepare_json ( const options_t * current,
const char * json,
size_t length,
options_t * candidate,
bool remote_only )

Definition at line 987 of file rcu.c.

988 {
989 yyjson_doc *doc = NULL;
991 size_t count = 0;
992 asciichat_error_t error = parse_json_edits(json, length, &doc, edits, &count);
993 options_patch_t patch = {.edits = edits, .count = count, .expected_revision = OPTIONS_REVISION_ANY};
994 if (error == ASCIICHAT_OK)
995 error = options_prepare_patch(current, &patch, candidate, remote_only);
996 yyjson_doc_free(doc);
997 return error;
998}

References ASCIICHAT_OK, OPTIONS_PATCH_MAX_EDITS, options_prepare_patch(), and OPTIONS_REVISION_ANY.

Referenced by acip_settings_request(), client_settings_receive(), session_participant_receive_settings(), and session_protocol_dispatch().

◆ options_prepare_patch()

asciichat_error_t options_prepare_patch ( const options_t * current,
const options_patch_t * patch,
options_t * candidate,
bool remote_only )

Prepare caller-owned state. The owner serializes access; remote edits use an allowlist.

Definition at line 799 of file rcu.c.

800 {
801 if (!current || !candidate || current == candidate || !patch || !patch->edits || !patch->count ||
803 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid options patch");
804 *candidate = *current;
805 for (size_t i = 0; i < patch->count; ++i) {
806 if (remote_only &&
808 return SET_ERRNO(ERROR_INVALID_PARAM, "Option is not a remote render preference");
809 asciichat_error_t error = edit_candidate(candidate, &patch->edits[i]);
810 if (error != ASCIICHAT_OK)
811 return error;
812 }
813 bool animation_changed = false;
814 bool stabilize_changed = false;
815 for (size_t i = 0; i < patch->count; ++i) {
816 const char *name = patch->edits[i].name;
817 animation_changed |= !strcmp(name, "matrix_rain") || !strcmp(name, "waveform") || !strcmp(name, "fft");
818 stabilize_changed |= !strcmp(name, "stabilize");
819 }
820 if (stabilize_changed)
821 candidate->stabilize_explicit = true;
822 else if (animation_changed && !candidate->stabilize_explicit)
823 candidate->stabilize = !(candidate->waveform || candidate->fft);
824 for (size_t i = 0; i < patch->count; ++i) {
825 asciichat_error_t error = validate_field(find_field(patch->edits[i].name), candidate);
826 if (error != ASCIICHAT_OK)
827 return error;
828 }
829 asciichat_error_t palette_error = validate_glyph_palette(candidate);
830 if (palette_error != ASCIICHAT_OK)
831 return palette_error;
832 candidate->flip_x_explicit |= current->flip_x_explicit;
833 options_resolve_flip_x(candidate);
834 return ASCIICHAT_OK;
835}
asciichat_error_t validate_glyph_palette(const options_t *opts)
Definition validation.c:25
void options_resolve_flip_x(options_t *opts)
Definition options.c:2575
bool options_remote_render_field(const char *name)
Definition rcu.c:671
options_operation_t operation
const char * name
bool flip_x_explicit
User selected an orientation for this process lifetime.
Definition options.h:1104
bool fft
Replace the video image with a live audio frequency spectrogram.
Definition options.h:1124
bool stabilize
Reduce frame-to-frame character flicker.
Definition options.h:1138
bool stabilize_explicit
Runtime preference was explicitly changed.
Definition options.h:1139
bool waveform
Replace the video image with a live audio waveform.
Definition options.h:1123

References ASCIICHAT_OK, options_patch_t::count, options_patch_t::edits, ERROR_INVALID_PARAM, options_state::fft, options_state::flip_x_explicit, options_edit_t::name, options_edit_t::operation, OPTIONS_ASSIGN, OPTIONS_PATCH_MAX_EDITS, options_remote_render_field(), options_resolve_flip_x(), SET_ERRNO, options_state::stabilize, options_state::stabilize_explicit, validate_glyph_palette(), and options_state::waveform.

Referenced by options_apply_patch(), and options_prepare_json().

◆ options_read_snapshot()

asciichat_error_t options_read_snapshot ( options_snapshot_t * snapshot)

Capture values and revision together. Callers own the copied snapshot.

Definition at line 865 of file rcu.c.

865 {
866 if (!snapshot || !lifecycle_is_initialized(&g_options_lifecycle))
867 return SET_ERRNO(ERROR_INVALID_STATE, "Options are not initialized");
868 mutex_lock(&g_options_write_mutex);
869 snapshot->values = *(options_t *)atomic_ptr_load(&g_options);
870 snapshot->revision = g_revision;
871 snapshot->origin = g_origin;
872 mutex_unlock(&g_options_write_mutex);
873 return ASCIICHAT_OK;
874}
options_origin_t origin

References ASCIICHAT_OK, ERROR_INVALID_STATE, options_snapshot_t::origin, options_snapshot_t::revision, SET_ERRNO, and options_snapshot_t::values.

Referenced by client_protocol_start(), initial_options(), session_protocol_update_settings(), and session_settings_from_options().

◆ options_remote_render_field()

bool options_remote_render_field ( const char * name)

Only explicitly exposed fields may enter a remote rendering patch.

Definition at line 671 of file rcu.c.

671 {
672 const runtime_field_t *field = find_field(name);
673 if (!field)
674 return false;
675 const char *allowed[] = {
676 "width", "height", "fps", "color_mode", "color_filter", "render_mode", "palette_type",
677 "palette_custom", "palette_explicit", "renderer", "stabilize", "matrix_rain"};
678 for (size_t i = 0; i < sizeof(allowed) / sizeof(*allowed); ++i)
679 if (!strcmp(field->name, allowed[i]))
680 return true;
681 return false;
682}
const char * name
Definition rcu.c:552

References runtime_field_t::name.

Referenced by options_prepare_patch(), and options_values_json().

◆ options_revision()

uint64_t options_revision ( void )

Observers coalesce changes by reading a new snapshot when this revision changes.

Definition at line 876 of file rcu.c.

876 {
877 if (!lifecycle_is_initialized(&g_options_lifecycle))
878 return 0;
879 mutex_lock(&g_options_write_mutex);
880 uint64_t revision = g_revision;
881 mutex_unlock(&g_options_write_mutex);
882 return revision;
883}
unsigned long long uint64_t
Definition common.h:63

Referenced by EMSCRIPTEN_BINDINGS(), and session_protocol_update_settings().

◆ options_toggle()

asciichat_error_t options_toggle ( const char * name)

Definition at line 911 of file rcu.c.

911 {
912 return apply_one((options_edit_t){.name = name, .type = OPTIONS_VALUE_BOOL, .operation = OPTIONS_TOGGLE});
913}

References OPTIONS_TOGGLE, and OPTIONS_VALUE_BOOL.

Referenced by ui_session_key().

◆ options_values_json()

char * options_values_json ( const options_t * values,
bool remote_only )

Caller releases JSON with SAFE_FREE. Only public runtime fields are serialized.

Definition at line 1013 of file rcu.c.

1013 {
1014 yyjson_mut_doc *doc = yyjson_mut_doc_new(&runtime_json_allocator);
1015 if (!doc)
1016 return NULL;
1017 yyjson_mut_val *root = yyjson_mut_obj(doc);
1018 yyjson_mut_doc_set_root(doc, root);
1019 for (size_t i = 0; i < sizeof(runtime_fields) / sizeof(*runtime_fields); ++i) {
1020 const runtime_field_t *field = &runtime_fields[i];
1021 bool exposed = options_remote_render_field(field->name);
1022 if (!remote_only &&
1023 (!strcmp(field->name, "flip_x") || !strcmp(field->name, "flip_x_explicit") ||
1024 !strcmp(field->name, "media_input") || !strcmp(field->name, "flip_y") || !strcmp(field->name, "waveform") ||
1025 !strcmp(field->name, "fft") || !strcmp(field->name, "fps_counter") || !strcmp(field->name, "audio_source") ||
1026 !strcmp(field->name, "speakers_volume") || !strcmp(field->name, "microphone_sensitivity") ||
1027 !strcmp(field->name, "audio_enabled")))
1028 exposed = true;
1029 if (!exposed)
1030 continue;
1031 const char *ptr = (const char *)values + field->offset;
1032 switch (field->type) {
1033 case OPTIONS_VALUE_INT:
1034 yyjson_mut_obj_add_int(doc, root, field->name, *(const int *)ptr);
1035 break;
1036 case OPTIONS_VALUE_BOOL:
1037 yyjson_mut_obj_add_bool(doc, root, field->name, *(const bool *)ptr);
1038 break;
1040 yyjson_mut_obj_add_real(doc, root, field->name,
1041 field->size == sizeof(float) ? *(const float *)ptr : *(const double *)ptr);
1042 break;
1044 yyjson_mut_obj_add_str(doc, root, field->name, ptr);
1045 break;
1046 }
1047 }
1048 char *json = yyjson_mut_write_opts(doc, 0, &runtime_json_allocator, NULL, NULL);
1049 yyjson_mut_doc_free(doc);
1050 return json;
1051}
options_value_type_t type
Definition rcu.c:553
size_t offset
Definition rcu.c:554
size_t size
Definition rcu.c:554

References runtime_field_t::name, runtime_field_t::offset, options_remote_render_field(), OPTIONS_VALUE_BOOL, OPTIONS_VALUE_DOUBLE, OPTIONS_VALUE_INT, OPTIONS_VALUE_STRING, runtime_field_t::size, and runtime_field_t::type.

Referenced by acip_settings_request(), acip_settings_send(), and client_settings_values().