mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
refactor: api_ressource => api_action and introduced new subdirectories
This commit is contained in:
parent
5c6188ccc2
commit
580189b678
8 changed files with 106 additions and 243 deletions
|
@ -20,7 +20,7 @@ struct lws;
|
|||
struct super_node;
|
||||
|
||||
struct api;
|
||||
struct api_ressource;
|
||||
struct api_action;
|
||||
|
||||
/** Callback type of command function
|
||||
*
|
||||
|
@ -29,7 +29,7 @@ struct api_ressource;
|
|||
* @param[out] resp JSON command response.
|
||||
* @param[in] i Execution context.
|
||||
*/
|
||||
typedef int (*api_cb_t)(struct api_ressource *c, json_t *args, json_t **resp, struct api_session *s);
|
||||
typedef int (*api_cb_t)(struct api_action *c, json_t *args, json_t **resp, struct api_session *s);
|
||||
|
||||
struct api {
|
||||
struct list sessions; /**< List of currently active connections */
|
||||
|
@ -39,11 +39,8 @@ struct api {
|
|||
struct super_node *super_node;
|
||||
};
|
||||
|
||||
/** Command descriptor
|
||||
*
|
||||
* Every command is described by a descriptor.
|
||||
*/
|
||||
struct api_ressource {
|
||||
/** API action descriptor */
|
||||
struct api_action {
|
||||
api_cb_t cb;
|
||||
};
|
||||
|
||||
|
@ -59,12 +56,6 @@ int api_start(struct api *a);
|
|||
|
||||
int api_stop(struct api *a);
|
||||
|
||||
int api_session_init(struct api_session *s, struct api *a, enum api_mode m);
|
||||
|
||||
int api_session_destroy(struct api_session *s);
|
||||
|
||||
int api_session_run_command(struct api_session *s, json_t *req, json_t **resp);
|
||||
|
||||
/** Libwebsockets callback for "api" endpoint */
|
||||
int api_ws_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ struct plugin {
|
|||
int (*unload)(struct plugin *p);
|
||||
|
||||
union {
|
||||
struct api_ressource api;
|
||||
struct api_action api;
|
||||
struct node_type node;
|
||||
struct fpga_ip_type ip;
|
||||
struct hook_type hook;
|
||||
|
|
219
lib/api.c
219
lib/api.c
|
@ -6,109 +6,70 @@
|
|||
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#include "plugin.h"
|
||||
#include "api.h"
|
||||
#include "log.h"
|
||||
#include "web.h"
|
||||
#include "config.h"
|
||||
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "assert.h"
|
||||
#include "compat.h"
|
||||
|
||||
int api_ws_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
|
||||
{
|
||||
//struct api_session *s = (struct api_session *) user;
|
||||
|
||||
switch (reason) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int api_http_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct web *w = lws_context_user(lws_get_context(wsi));
|
||||
struct api_session *s = (struct api_session *) user;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_ESTABLISHED: {
|
||||
struct web *w = (struct web *) lws_context_user(lws_get_context(wsi));
|
||||
|
||||
if (w->api == NULL)
|
||||
return -1; /** @todo return error message */
|
||||
|
||||
api_session_init(s, w->api, API_MODE_WS);
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_HTTP: {
|
||||
struct web *w = (struct web *) lws_context_user(lws_get_context(wsi));
|
||||
|
||||
char *uri = (char *) in;
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
if (w->api == NULL) {
|
||||
lws_close_reason(wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR, (unsigned char *) "API disabled", strlen("API disabled"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse request URI */
|
||||
ret = sscanf(uri, "/api/v%d", (int *) &s->version);
|
||||
char uri[64];
|
||||
lws_hdr_copy(wsi, uri, sizeof(uri), WSI_TOKEN_GET_URI); /* The path component of the*/
|
||||
|
||||
ret = sscanf(uri, "/v%d", (int *) &s->version);
|
||||
if (ret != 1)
|
||||
return -1;
|
||||
|
||||
debug(LOG_API, "New REST API session initiated: version = %d", s->version);
|
||||
|
||||
api_session_init(s, w->api, API_MODE_HTTP);
|
||||
|
||||
/* Prepare HTTP response header */
|
||||
const char headers[] = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-type: application/json\r\n"
|
||||
"User-agent: " USER_AGENT "\r\n"
|
||||
"\r\n";
|
||||
|
||||
api_buffer_append(&s->response.headers, headers, sizeof(headers)-1);
|
||||
|
||||
/* book us a LWS_CALLBACK_HTTP_WRITEABLE callback */
|
||||
lws_callback_on_writable(wsi);
|
||||
ret = api_session_init(s, w->api, API_MODE_WS);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
debug(LOG_API, "New API session initiated: version=%d, mode=websocket", s->version);
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
case LWS_CALLBACK_HTTP_BODY: {
|
||||
api_buffer_append(&s->request.body, in, len);
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
ret = api_session_destroy(s);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
json_t *req, *resp;
|
||||
while (api_parse_request(&s->request.body, &req) == 1) {
|
||||
api_session_run_command(s, req, &resp);
|
||||
api_unparse_response(&s->response.body, resp);
|
||||
|
||||
lws_callback_on_writable(wsi);
|
||||
}
|
||||
debug(LOG_API, "Closed API session");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
||||
s->completed = true;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
/* We send headers only in HTTP mode */
|
||||
if (s->mode == API_MODE_HTTP)
|
||||
api_buffer_send(&s->response.headers, wsi, LWS_WRITE_HTTP_HEADERS);
|
||||
web_buffer_write(&s->response.body, wsi);
|
||||
|
||||
api_buffer_send(&s->response.body, wsi, LWS_WRITE_HTTP);
|
||||
|
||||
if (s->completed && s->response.body.len == 0)
|
||||
return -1;
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
web_buffer_append(&s->request.body, in, len);
|
||||
|
||||
json_t *req, *resp;
|
||||
while (web_buffer_read_json(&s->request.body, &req) >= 0) {
|
||||
api_session_run_command(s, req, &resp);
|
||||
|
||||
web_buffer_append_json(&s->response.body, resp);
|
||||
lws_callback_on_writable(wsi);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
|
@ -117,32 +78,75 @@ int api_http_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void
|
|||
return 0;
|
||||
}
|
||||
|
||||
int api_buffer_send(struct api_buffer *b, struct lws *w, enum lws_write_protocol prot)
|
||||
int api_http_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
|
||||
{
|
||||
int sent;
|
||||
|
||||
if (b->len <= 0)
|
||||
return 0;
|
||||
int ret;
|
||||
|
||||
sent = lws_write(w, (unsigned char *) b->buf, b->len, prot);
|
||||
if (sent > 0) {
|
||||
memmove(b->buf, b->buf + sent, sent);
|
||||
b->len -= sent;
|
||||
struct web *w = lws_context_user(lws_get_context(wsi));
|
||||
struct api_session *s = (struct api_session *) user;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_HTTP:
|
||||
if (w->api == NULL) {
|
||||
lws_close_reason(wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR, (unsigned char *) "API disabled", strlen("API disabled"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse request URI */
|
||||
ret = sscanf(in, "/api/v%d", (int *) &s->version);
|
||||
if (ret != 1)
|
||||
return -1;
|
||||
|
||||
ret = api_session_init(s, w->api, API_MODE_HTTP);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
debug(LOG_API, "New API session initiated: version=%d, mode=http", s->version);
|
||||
|
||||
/* Prepare HTTP response header */
|
||||
const char headers[] = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-type: application/json\r\n"
|
||||
"User-agent: " USER_AGENT "\r\n"
|
||||
"\r\n";
|
||||
|
||||
web_buffer_append(&s->response.headers, headers, sizeof(headers)-1);
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED_HTTP:
|
||||
ret = api_session_destroy(s);
|
||||
if (ret)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY:
|
||||
web_buffer_append(&s->request.body, in, len);
|
||||
|
||||
json_t *req, *resp;
|
||||
while (web_buffer_read_json(&s->request.body, &req) == 1) {
|
||||
api_session_run_command(s, req, &resp);
|
||||
|
||||
web_buffer_append_json(&s->response.body, resp);
|
||||
lws_callback_on_writable(wsi);
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
||||
s->completed = true;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
web_buffer_write(&s->response.headers, wsi);
|
||||
web_buffer_write(&s->response.body, wsi);
|
||||
|
||||
if (s->completed && s->response.body.len == 0)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
int api_buffer_append(struct api_buffer *b, const char *in, size_t len)
|
||||
{
|
||||
b->buf = realloc(b->buf, b->len + len);
|
||||
if (!b->buf)
|
||||
return -1;
|
||||
|
||||
memcpy(b->buf + b->len, in, len);
|
||||
|
||||
b->len += len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -186,26 +190,3 @@ int api_stop(struct api *a)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int api_session_init(struct api_session *s, struct api *a, enum api_mode m)
|
||||
{
|
||||
s->mode = m;
|
||||
s->api = a;
|
||||
|
||||
s->completed = false;
|
||||
|
||||
s->request.body =
|
||||
s->response.body =
|
||||
s->response.headers = (struct api_buffer) {
|
||||
.buf = NULL,
|
||||
.size = 0,
|
||||
.len = 0
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int api_session_destroy(struct api_session *s)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
LIB_SRCS += $(wildcard lib/apis/*.c)
|
|
@ -1,31 +0,0 @@
|
|||
/** The "config" command
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
|
||||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "utils.h"
|
||||
#include "plugin.h"
|
||||
|
||||
static int api_config(struct api_ressource *h, json_t *args, json_t **resp, struct api_session *s)
|
||||
{
|
||||
config_setting_t *cfg_root = config_root_setting(&s->api->super_node->cfg);
|
||||
|
||||
*resp = cfg_root ? config_to_json(cfg_root) : json_object();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct plugin p = {
|
||||
.name = "config",
|
||||
.description = "retrieve current VILLASnode configuration",
|
||||
.type = PLUGIN_TYPE_API,
|
||||
.api.cb = api_config
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN(&p)
|
|
@ -1,52 +0,0 @@
|
|||
/** The "nodes" command
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
|
||||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
#include "plugin.h"
|
||||
#include "api.h"
|
||||
#include "node.h"
|
||||
#include "utils.h"
|
||||
|
||||
extern struct list nodes;
|
||||
|
||||
static int api_nodes(struct api_ressource *r, json_t *args, json_t **resp, struct api_session *s)
|
||||
{
|
||||
json_t *json_nodes = json_array();
|
||||
|
||||
for (size_t i = 0; i < list_length(&s->api->super_node->nodes); i++) {
|
||||
struct node *n = list_at(&s->api->super_node->nodes, i);
|
||||
|
||||
json_t *json_node = json_pack("{ s: s, s: i, s: i, s: i, s: i }",
|
||||
"name", node_name_short(n),
|
||||
"state", n->state,
|
||||
"vectorize", n->vectorize,
|
||||
"affinity", n->affinity,
|
||||
"id", i
|
||||
);
|
||||
|
||||
/* Add all additional fields of node here.
|
||||
* This can be used for metadata */
|
||||
json_object_update(json_node, config_to_json(n->cfg));
|
||||
|
||||
json_array_append_new(json_nodes, json_node);
|
||||
}
|
||||
|
||||
*resp = json_nodes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct plugin p = {
|
||||
.name = "nodes",
|
||||
.description = "retrieve list of all known nodes",
|
||||
.type = PLUGIN_TYPE_API,
|
||||
.api.cb = api_nodes
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN(&p)
|
|
@ -1,25 +0,0 @@
|
|||
/** The "reload" command
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
|
||||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
*********************************************************************************/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "api.h"
|
||||
|
||||
/** @todo not implemented yet */
|
||||
static int api_reload(struct api_ressource *h, json_t *args, json_t **resp, struct api_session *s)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct plugin p = {
|
||||
.name = "reload",
|
||||
.description = "restart VILLASnode with new configuration",
|
||||
.type = PLUGIN_TYPE_API,
|
||||
.api.cb = api_reload
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN(&p)
|
|
@ -12,7 +12,7 @@
|
|||
#include "utils.h"
|
||||
#include "log.h"
|
||||
#include "web.h"
|
||||
#include "api.h"
|
||||
#include "api/session.h"
|
||||
|
||||
#include "nodes/websocket.h"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue