Referencia de la API del núcleo
Referencia completa de todos los tipos, métodos, códigos de estado y punteros de función disponibles para los módulos. Incluye un solo header: portal/portal.h
Un solo header. Todo lo que un module necesita se expone a través de portal/portal.h. La API del core es intencionalmente pequeña — cada puntero de función en portal_core_t existe porque un module no puede hacer su trabajo sin él.
1. Tipos
portal_header_t — Par clave-valor
La unidad fundamental para los metadatos de un mensaje. Los headers transportan información auxiliar junto al body.
typedef struct {
char *key;
char *value;
} portal_header_t;
portal_labels_t — Conjunto de etiquetas
Las etiquetas controlan el acceso a los path. Un path puede requerir una o más etiquetas; solo los usuarios autenticados (o módulos) cuyo token contenga etiquetas coincidentes pueden acceder a él.
typedef struct {
char labels[PORTAL_MAX_LABELS][PORTAL_MAX_LABEL_LEN];
int count;
} portal_labels_t;
| Función | Firma | Descripción |
portal_labels_add | (portal_labels_t *set, const char *label) | Añadir una etiqueta al conjunto |
portal_labels_remove | (portal_labels_t *set, const char *label) | Eliminar una etiqueta del conjunto |
portal_labels_has | (portal_labels_t *set, const char *label) | Comprobar si una etiqueta existe en el conjunto |
portal_labels_intersects | (portal_labels_t *a, portal_labels_t *b) | Comprobar si dos conjuntos comparten alguna etiqueta |
portal_labels_clear | (portal_labels_t *set) | Eliminar todas las etiquetas del conjunto |
portal_msg_t — El mensaje universal
Cada petición, comando, evento y suscripción fluye a través de esta única estructura. Esto es la Ley 2 en código.
typedef struct {
uint64_t id;
char *path;
uint8_t method;
uint16_t header_count;
portal_header_t *headers;
void *body;
size_t body_len;
portal_ctx_t *ctx; // auth + trace
} portal_msg_t;
| Función | Firma | Descripción |
portal_msg_alloc | (void) | Asignar un nuevo mensaje vacío |
portal_msg_free | (portal_msg_t *msg) | Liberar el mensaje y toda la memoria asociada |
portal_msg_set_path | (portal_msg_t *msg, const char *path) | Establecer el path de destino |
portal_msg_set_method | (portal_msg_t *msg, uint8_t method) | Establecer el método (GET, SET, CALL...) |
portal_msg_set_body | (portal_msg_t *msg, const void *data, size_t len) | Establecer el body (copia los datos) |
portal_msg_add_header | (portal_msg_t *msg, const char *key, const char *value) | Añadir un header clave-valor |
portal_resp_t — Respuesta
Devuelta por las llamadas síncronas de send. Contiene un código de estado, headers opcionales y un body.
typedef struct {
uint16_t status;
uint16_t header_count;
portal_header_t *headers;
void *body;
size_t body_len;
} portal_resp_t;
| Función | Firma | Descripción |
portal_resp_alloc | (void) | Asignar una nueva respuesta vacía |
portal_resp_free | (portal_resp_t *resp) | Liberar la respuesta y toda la memoria asociada |
portal_resp_set_status | (portal_resp_t *resp, uint16_t status) | Establecer el código de estado |
portal_resp_set_body | (portal_resp_t *resp, const void *data, size_t len) | Establecer el body de la respuesta (copia los datos) |
portal_ctx_t — Contexto del mensaje
Adjunto a cada mensaje. Contiene las credenciales de autenticación y la información de trazabilidad distribuida. El core lo rellena automáticamente — los módulos lo leen pero nunca lo falsifican.
typedef struct {
portal_auth_t auth; // user + token + labels
portal_trace_t trace; // trace_id, parent_id, timestamp_us, hops
char *source_node;
char *source_module;
} portal_ctx_t;
2. Métodos
Siete métodos cubren todos los patrones de interacción posibles. Cada mensaje lleva exactamente uno.
| Constante | Valor | Descripción |
PORTAL_METHOD_GET | 0x01 | Leer un recurso, sin efectos secundarios |
PORTAL_METHOD_SET | 0x02 | Crear o actualizar un recurso |
PORTAL_METHOD_CALL | 0x03 | Ejecutar una acción |
PORTAL_METHOD_EVENT | 0x04 | Notificación sin esperar respuesta |
PORTAL_METHOD_SUB | 0x05 | Suscribirse a eventos en un path |
PORTAL_METHOD_UNSUB | 0x06 | Cancelar la suscripción a eventos |
PORTAL_METHOD_META | 0x07 | Consultar metadatos del path (modo de acceso, etiquetas, propietario) |
3. Códigos de estado
Inspirados en HTTP pero reducidos a lo esencial. Cada respuesta lleva exactamente un código de estado.
| Código | Constante | Significado |
200 | PORTAL_OK | Éxito |
201 | PORTAL_CREATED | Recurso creado |
202 | PORTAL_ACCEPTED | Petición aceptada, procesamiento asíncrono |
400 | PORTAL_BAD_REQUEST | Mensaje malformado o parámetros inválidos |
401 | PORTAL_UNAUTHORIZED | Autenticación requerida o token inválido |
403 | PORTAL_FORBIDDEN | Autenticado pero etiquetas insuficientes |
404 | PORTAL_NOT_FOUND | El path no existe |
409 | PORTAL_CONFLICT | Recurso bloqueado o conflicto de versión |
500 | PORTAL_INTERNAL_ERROR | Fallo en el module |
503 | PORTAL_UNAVAILABLE | Module no cargado o nodo inalcanzable |
4. API del core (portal_core_t)
Cada module recibe un puntero portal_core_t al cargarse. Esta es la única interfaz del module con el sistema. Toda interacción con el core, otros módulos, eventos, almacenamiento y configuración pasa a través de estos punteros de función.
La Ley 3 en la práctica. El core no hace nada — pero proporciona a los módulos todo lo que necesitan. Cada puntero de función a continuación existe porque un module no puede hacer su trabajo sin él.
Gestión de path
| Puntero de función | Firma | Descripción |
path_register | (core, const char *path, const char *module_name) | Registrar un path perteneciente a este module |
path_unregister | (core, const char *path) | Liberar un path previamente registrado |
path_set_access | (core, const char *path, uint8_t mode) | Establecer el modo de acceso: READ, WRITE o RW (Ley 8) |
path_add_label | (core, const char *path, const char *label) | Requerir esta etiqueta para acceder al path |
path_remove_label | (core, const char *path, const char *label) | Eliminar una restricción de etiqueta del path |
Enrutamiento de mensajes
| Puntero de función | Firma | Descripción |
send | (core, portal_msg_t *msg, portal_resp_t *resp) | Enviar un mensaje a cualquier path, local o remoto. Bloquea hasta recibir respuesta. |
Consultas de módulos
| Puntero de función | Firma | Descripción |
module_loaded | (core, const char *name) | Comprobar si un module está actualmente cargado y disponible |
Event loop
| Puntero de función | Firma | Descripción |
fd_add | (core, int fd, uint32_t events, callback, userdata) | Registrar un descriptor de archivo para E/S asíncrona (Ley 13) |
fd_del | (core, int fd) | Eliminar un descriptor de archivo del event loop |
timer_add | (core, uint64_t interval, callback, userdata) | Registrar un temporizador periódico (intervalo en milisegundos) |
Eventos
| Puntero de función | Firma | Descripción |
event_register | (core, const char *path, const char *description, portal_labels_t *labels) | Declarar un evento que este module puede emitir |
event_unregister | (core, const char *path) | Eliminar una declaración de evento |
event_emit | (core, const char *path, const void *data, size_t len) | Disparar un evento a todos los suscriptores (Ley 10) |
Pub/Sub
| Puntero de función | Firma | Descripción |
subscribe | (core, const char *pattern, handler, userdata) | Suscribirse a eventos que coincidan con un patrón de path |
unsubscribe | (core, const char *pattern, handler) | Cancelar la suscripción de un handler previamente registrado |
Almacenamiento
| Puntero de función | Firma | Descripción |
storage_register | (core, portal_storage_provider_t *provider) | Registrar un backend de almacenamiento (clave-valor, SQL, etc.) |
Configuración
| Puntero de función | Firma | Descripción |
config_get | (core, const char *module, const char *key) | Leer un valor de configuración de un module (Ley 11) |
Registro de log
| Puntero de función | Firma | Descripción |
log | (core, uint8_t level, const char *module, const char *fmt, ...) | Escribir una entrada de log en el nivel especificado |
Niveles de log:
| Constante | Valor | Uso |
PORTAL_LOG_ERROR | 0 | Fallos que requieren atención inmediata |
PORTAL_LOG_WARN | 1 | Condiciones inesperadas pero recuperables |
PORTAL_LOG_INFO | 2 | Mensajes operacionales normales |
PORTAL_LOG_DEBUG | 3 | Información de diagnóstico detallada |
PORTAL_LOG_TRACE | 4 | Trazado por mensaje, alto volumen |
Bloqueo de recursos
Los recursos físicos (puertos serie, GPIO, dispositivos IoT) requieren acceso exclusivo. Estas funciones implementan la Ley 14 — bloqueo automático en la primera escritura, keepalive y liberación automática tras inactividad.
| Puntero de función | Firma | Descripción |
resource_lock | (core, const char *resource, const char *owner) | Adquirir bloqueo exclusivo sobre un recurso |
resource_unlock | (core, const char *resource, const char *owner) | Liberar un bloqueo retenido |
resource_keepalive | (core, const char *resource, const char *owner) | Reiniciar el temporizador de inactividad de 60 segundos |
resource_locked | (core, const char *resource) | Comprobar si un recurso está actualmente bloqueado |
resource_owner | (core, const char *resource) | Devolver el propietario actual del bloqueo (o NULL) |
5. Constantes
Límites
| Constante | Valor | Descripción |
PORTAL_MAX_PATH_LEN | 1024 | Longitud máxima del path en bytes |
PORTAL_MAX_MODULE_NAME | 64 | Longitud máxima del nombre de module |
PORTAL_MAX_MODULES | 256 | Máximo de módulos cargados simultáneamente |
PORTAL_MAX_HEADERS | 32 | Máximo de headers por mensaje |
PORTAL_MAX_EVENTS | 64 | Máximo de eventos por module |
PORTAL_MAX_LABELS | 32 | Máximo de etiquetas por conjunto |
PORTAL_MAX_LABEL_LEN | 64 | Longitud máxima de la cadena de etiqueta |
Modos de acceso
| Constante | Valor | Descripción |
PORTAL_ACCESS_READ | 0x01 | El path acepta solo GET y META |
PORTAL_ACCESS_WRITE | 0x02 | El path acepta solo SET y CALL |
PORTAL_ACCESS_RW | 0x03 | El path acepta todos los métodos |
6. Path internos del core
El core registra estos path al iniciar. Están siempre disponibles, incluso sin módulos cargados.
/core — Estado del core
| Path | Método | Descripción |
/core/status | GET | Devuelve tiempo de actividad, versión y número de módulos cargados |
/core/modules | GET | Listar todos los módulos cargados y su estado |
/core/modules/{name} | GET | Detalles de un module específico |
/core/modules/{name}/load | CALL | Cargar un module en tiempo de ejecución (Ley 5) |
/core/modules/{name}/unload | CALL | Descargar un module en tiempo de ejecución |
/core/modules/{name}/reload | CALL | Recargar un module (descarga + carga) |
/core/paths | GET | Listar todos los path registrados con sus modos de acceso |
/core/config/{module}/{key} | GET | Leer un valor de configuración de un module |
/core/config/{module}/{key} | SET | Actualizar un valor de configuración de un module |
/core/log/level | GET | Nivel de log global actual |
/core/log/level | SET | Cambiar el nivel de log global en tiempo de ejecución |
/auth — Autenticación
| Path | Método | Descripción |
/auth/login | CALL | Autenticar con usuario + contraseña, devuelve un token |
/auth/logout | CALL | Invalidar el token actual |
/auth/verify | CALL | Verificar un token y devolver sus etiquetas |
/users — Gestión de usuarios
| Path | Método | Descripción |
/users | GET | Listar todos los usuarios |
/users/{id} | GET | Obtener detalles del usuario |
/users/{id} | SET | Crear o actualizar un usuario |
/users/{id}/labels | GET | Obtener el conjunto de etiquetas del usuario |
/users/{id}/labels | SET | Reemplazar el conjunto de etiquetas del usuario |
/groups — Gestión de grupos
| Path | Método | Descripción |
/groups | GET | Listar todos los grupos |
/groups/{id} | GET | Obtener detalles del grupo y lista de miembros |
/groups/{id} | SET | Crear o actualizar un grupo |
/groups/{id}/members | GET | Listar miembros del grupo |
/groups/{id}/members | SET | Añadir o eliminar miembros |
/events — Registro de eventos
| Path | Método | Descripción |
/events | GET | Listar todos los eventos registrados |
/events/{path} | GET | Obtener descripción del evento, etiquetas y número de suscriptores |
/events/{path} | SUB | Suscribirse a un evento |
/events/{path} | UNSUB | Cancelar la suscripción a un evento |
7. Patrones de comunicación
Petición / Respuesta
El patrón síncrono estándar. Un module envía un mensaje y se bloquea hasta que el module de destino responde. Se utiliza para GET, SET, CALL y META.
portal_msg_t *msg = portal_msg_alloc();
portal_resp_t *resp = portal_resp_alloc();
portal_msg_set_path(msg, "/local/db/users/1");
portal_msg_set_method(msg, PORTAL_METHOD_GET);
int rc = core->send(core, msg, resp);
if (rc == PORTAL_OK && resp->status == PORTAL_OK) {
// resp->body contains the user record
process_user(resp->body, resp->body_len);
}
portal_msg_free(msg);
portal_resp_free(resp);
Disparar y olvidar (Eventos)
Un productor de eventos emite datos a un path. Todos los suscriptores los reciben de forma asíncrona. El productor no espera y no sabe quién (o si alguien) los recibió. Se utiliza con PORTAL_METHOD_EVENT.
// Producer: emit an event
const char *payload = "{\"temp\":22.5,\"unit\":\"C\"}";
core->event_emit(core, "/local/iot/sensor/temperature",
payload, strlen(payload));
// Consumer: subscribe to events (registered once, usually in module_load)
static void on_temperature(const char *path,
const void *data, size_t len,
void *userdata) {
core->log(core, PORTAL_LOG_INFO, "dashboard",
"temperature update: %.*s", (int)len, (const char *)data);
}
core->subscribe(core, "/local/iot/sensor/*", on_temperature, NULL);
Patrón o coincidencia exacta. La función subscribe acepta patrones glob. /local/iot/sensor/* coincide con cualquier evento bajo ese prefijo. Las rutas exactas también funcionan.