Pharos 0.7.23
Modern Web Framework & Web App Hosting Service.
Loading...
Searching...
No Matches
native_runtime_stack.c
Go to the documentation of this file.
1/**
2 * @file
3 * @brief Resolves the runtime apps directory, fingerprints it for reload detection, logs startup state, and matches requests to mounted apps.
4 */
5
7
8#include "native_app_config.h"
10#include "native_support.h"
11
12#ifndef PHAROS_RUNTIME_STACK_VERSION
13#define PHAROS_RUNTIME_STACK_VERSION "0.7.23"
14#endif
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20
21#ifdef _WIN32
22#define native_runtime_stack_strdup _strdup
23#else
24#include <unistd.h>
25#define native_runtime_stack_strdup strdup
26#endif
27
28static char *shell_quote_runtime_stack_native(const char *value) {
29 size_t len = 2;
30 const char *cursor;
31 char *quoted;
32 char *out;
33 if (value == NULL) {
34 return native_runtime_stack_strdup("''");
35 }
36 for (cursor = value; *cursor != '\0'; cursor++) {
37 if (*cursor == '\'') {
38 len += 4;
39 } else {
40 len += 1;
41 }
42 }
43 quoted = (char *)malloc(len + 1);
44 if (quoted == NULL) {
45 return NULL;
46 }
47 out = quoted;
48 *out++ = '\'';
49 for (cursor = value; *cursor != '\0'; cursor++) {
50 if (*cursor == '\'') {
51 memcpy(out, "'\\''", 4);
52 out += 4;
53 } else {
54 *out++ = *cursor;
55 }
56 }
57 *out++ = '\'';
58 *out = '\0';
59 return quoted;
60}
61
62char *runtime_apps_dir_native(const char *conf_path) {
63 char *raw = NULL;
64 char *resolved = NULL;
65 if (conf_path == NULL || conf_path[0] == '\0') {
67 }
68 raw = conf_lookup_value(conf_path, "apps_dir");
69 if (raw == NULL || raw[0] == '\0') {
70 free(raw);
72 }
73 resolved = resolve_conf_relative_path_native(conf_path, raw);
74 free(raw);
75 return resolved;
76}
77
78char *runtime_apps_fingerprint_native(const char *apps_dir) {
79#ifndef __wasm__
80 char *quoted_apps_dir = NULL;
81 char command[16384];
82 FILE *pipe = NULL;
83 char buffer[256];
84 char *fingerprint = NULL;
85 if (apps_dir == NULL || apps_dir[0] == '\0') {
86 return NULL;
87 }
88 quoted_apps_dir = shell_quote_runtime_stack_native(apps_dir);
89 if (quoted_apps_dir == NULL) {
90 return NULL;
91 }
92 snprintf(
93 command,
94 sizeof(command),
95 "find %s -mindepth 1 -maxdepth 2 \\( -name pharos.app.json -o -name app.conf -o -path '*/runtime/*' \\) -type f -print 2>/dev/null | sort | xargs cat 2>/dev/null | shasum -a 256",
96 quoted_apps_dir
97 );
98 free(quoted_apps_dir);
99 pipe = popen(command, "r");
100 if (pipe == NULL) {
101 return NULL;
102 }
103 if (fgets(buffer, sizeof(buffer), pipe) != NULL) {
104 size_t len = strcspn(buffer, " \t\r\n");
105 fingerprint = dup_range(buffer, len);
106 }
107 pclose(pipe);
108 return fingerprint;
109#else
110 (void)apps_dir;
111 return NULL;
112#endif
113}
114
115static void runtime_loaded_app_context_native(const AppRuntime *app, char *buffer, size_t buffer_len) {
116 const char *mount = app != NULL && app->base_path != NULL ? app->base_path : "";
117 const char *context = mount;
118 if (context[0] == '/') {
119 context++;
120 }
121 if (context[0] == '\0') {
122 context = app != NULL && app->app_id != NULL ? app->app_id : "";
123 }
124 snprintf(buffer, buffer_len, "%s", context);
125}
126
127void runtime_log_banner_native(const RuntimeStack *stack, const ServeConfig *config, long load_ms) {
128 Buffer loaded_apps;
129 size_t i;
130 time_t now = time(NULL);
131 struct tm tm_utc;
132 char timestamp[32];
133 char context[256];
134 buffer_init(&loaded_apps);
135#ifdef _WIN32
136 gmtime_s(&tm_utc, &now);
137#else
138 gmtime_r(&now, &tm_utc);
139#endif
140 strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%SZ", &tm_utc);
141 for (i = 0; i < stack->count; i++) {
142 runtime_loaded_app_context_native(&stack->apps[i], context, sizeof(context));
143 if (context[0] == '\0') {
144 continue;
145 }
146 if (loaded_apps.len > 0) {
147 buffer_append(&loaded_apps, ",", 1);
148 }
149 buffer_append(&loaded_apps, context, strlen(context));
150 }
151 printf("%s INFO Pharos %s threaded: true\n", timestamp, PHAROS_RUNTIME_STACK_VERSION);
152 printf("%s INFO app_count: %zu\n", timestamp, stack->count);
153 printf("%s INFO loaded_apps: %s\n", timestamp, loaded_apps.data != NULL ? loaded_apps.data : "");
154 printf("%s STATUS listening_on: %s started in: %ldms\n",
155 timestamp,
156 config->socket_path != NULL ? config->socket_path : config->host,
157 load_ms);
158 fflush(stdout);
159 buffer_free(&loaded_apps);
160}
161
163 AppRuntime *best = NULL;
164 size_t best_len = 0;
165 size_t index;
166 for (index = 0; index < stack->count; index++) {
167 AppRuntime *app = &stack->apps[index];
168 const char *mount = app->base_path != NULL ? app->base_path : "";
169 size_t mount_len = strlen(mount);
170 if (mount_len == 0) {
171 if (best == NULL) {
172 best = app;
173 }
174 continue;
175 }
176 if (strcmp(path, mount) == 0 || (starts_with(path, mount) && (path[mount_len] == '/' || path[mount_len] == '\0' || path[mount_len] == '?'))) {
177 if (mount_len > best_len) {
178 best = app;
179 best_len = mount_len;
180 }
181 }
182 }
183 return best;
184}
char * resolve_conf_relative_path_native(const char *conf_path, const char *raw_value)
Resolves a config value relative to the directory that owns a config file.
Declares app-local runtime configuration helpers and the app-local configuration record.
char * conf_lookup_value(const char *path, const char *key)
Reads a Pharos conf file and looks up one key.
Declares lightweight JSON and conf value lookup helpers.
char * runtime_apps_dir_native(const char *conf_path)
Resolves the apps directory configured for a runtime config file.
#define PHAROS_RUNTIME_STACK_VERSION
char * runtime_apps_fingerprint_native(const char *apps_dir)
Builds a fingerprint string describing the current runtime apps directory state.
static void runtime_loaded_app_context_native(const AppRuntime *app, char *buffer, size_t buffer_len)
static char * shell_quote_runtime_stack_native(const char *value)
#define native_runtime_stack_strdup
void runtime_log_banner_native(const RuntimeStack *stack, const ServeConfig *config, long load_ms)
Emits a startup banner describing the loaded runtime stack.
AppRuntime * runtime_match_app_native(RuntimeStack *stack, const char *path)
Finds the loaded app runtime that should handle a request path.
Declares runtime stack helpers for app discovery, reload detection, and request matching.
void buffer_init(Buffer *buffer)
Initializes a growable buffer to an empty state.
char * dup_range(const char *start, size_t len)
Duplicates a byte range into a newly allocated NUL-terminated string.
void buffer_free(Buffer *buffer)
Releases memory owned by a growable buffer.
char * current_working_directory(void)
Returns the current working directory.
int buffer_append(Buffer *buffer, const void *data, size_t len)
Appends bytes to a growable buffer and maintains a trailing NUL byte.
int starts_with(const char *value, const char *prefix)
Tests whether one string starts with another string.
Declares shared low-level support helpers used across the Pharos native runtime.
Loaded runtime metadata for one Pharos app artifact.
Growable byte buffer used by parsing and string assembly helpers.
size_t len
char * data
In-memory collection of loaded app runtimes served by one listener.
AppRuntime apps[MAX_APPS]
Parsed native serve configuration used to bootstrap the runtime listener.
const char size_t len
Definition yyjson.h:8364