1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
18414: gcoap/fileserver: add event callbacks r=benpicco a=benpicco



Co-authored-by: Benjamin Valentin <benjamin.valentin@ml-pa.com>
This commit is contained in:
bors[bot] 2023-01-16 22:23:46 +00:00 committed by GitHub
commit d6f44f6206
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 136 additions and 0 deletions

View File

@ -21,6 +21,7 @@ USEMODULE += shell_cmds_default
# enable the fileserver module
USEMODULE += gcoap_fileserver
USEMODULE += gcoap_fileserver_callback
USEMODULE += gcoap_fileserver_delete
USEMODULE += gcoap_fileserver_put

View File

@ -17,6 +17,7 @@
* @}
*/
#include <stdio.h>
#include "kernel_defines.h"
#include "net/gcoap.h"
#include "net/gcoap/fileserver.h"
@ -45,11 +46,36 @@ static gcoap_listener_t _listener = {
.resources_len = ARRAY_SIZE(_resources),
};
static void _event_cb(gcoap_fileserver_event_t event, gcoap_fileserver_event_ctx_t *ctx)
{
switch (event) {
case GCOAP_FILESERVER_GET_FILE_START:
printf("gcoap fileserver: Download started: %s\n", ctx->path);
break;
case GCOAP_FILESERVER_GET_FILE_END:
printf("gcoap fileserver: Download finished: %s\n", ctx->path);
break;
case GCOAP_FILESERVER_PUT_FILE_START:
printf("gcoap fileserver: Upload started: %s\n", ctx->path);
break;
case GCOAP_FILESERVER_PUT_FILE_END:
printf("gcoap fileserver: Upload finished: %s\n", ctx->path);
break;
case GCOAP_FILESERVER_DELETE_FILE:
printf("gcoap fileserver: Delete %s\n", ctx->path);
break;
}
}
int main(void)
{
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
gcoap_register_listener(&_listener);
if (IS_USED(MODULE_GCOAP_FILESERVER_CALLBACK)) {
gcoap_fileserver_set_event_cb(_event_cb, NULL);
}
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);

View File

@ -76,6 +76,7 @@ PSEUDOMODULES += fatfs_vfs_format
PSEUDOMODULES += fmt_%
PSEUDOMODULES += gcoap_forward_proxy
PSEUDOMODULES += gcoap_fileserver
PSEUDOMODULES += gcoap_fileserver_callback
PSEUDOMODULES += gcoap_fileserver_delete
PSEUDOMODULES += gcoap_fileserver_put
PSEUDOMODULES += gcoap_dtls

View File

@ -90,6 +90,51 @@ extern "C" {
*/
#define COAPFILESERVER_DIR_DELETE_ETAG (0x6ce88b56u)
/**
* @brief GCoAP fileserver event types
*
* @note This requires the gcoap_fileserver_callback module.
*/
typedef enum {
GCOAP_FILESERVER_GET_FILE_START, /**< file download started */
GCOAP_FILESERVER_GET_FILE_END, /**< file download finished */
GCOAP_FILESERVER_PUT_FILE_START, /**< file upload started */
GCOAP_FILESERVER_PUT_FILE_END, /**< file upload finished */
GCOAP_FILESERVER_DELETE_FILE, /**< file deletion requested
(called before file is deleted) */
} gcoap_fileserver_event_t;
/**
* @brief GCoAP fileserver event context
*/
typedef struct {
const char *path; /**< VFS path of the affected file */
void *user_ctx; /**< Optional user supplied context */
} gcoap_fileserver_event_ctx_t;
/**
* @brief GCoAP fileserver event callback type
*
* @param[in] event Type of the event
* @param[in] ctx Event context information
*
*/
typedef void (*gcoap_fileserver_event_handler_t)(gcoap_fileserver_event_t event,
gcoap_fileserver_event_ctx_t *ctx);
/**
* @brief Register a consumer for GCoAP fileserver events
* Requires the `gcoap_fileserver_callback` module
*
* The Callback is called on each fileserver event and executed
* within the GCoAP thread.
*
* @param[in] cb The callback function to be called on events
* @param[in] arg Custom callback function context
*
*/
void gcoap_fileserver_set_event_cb(gcoap_fileserver_event_handler_t cb, void *arg);
/**
* @brief File server handler
*

View File

@ -34,6 +34,21 @@
/** Maximum length of an expressible path, including the trailing 0 character. */
#define COAPFILESERVER_PATH_MAX (64)
/**
* @brief fileserver event callback, only used with `gcoap_fileserver_callback`
*/
static gcoap_fileserver_event_handler_t _event_cb;
/**
* @brief fileserver event callback context, only used with `gcoap_fileserver_callback`
*/
static void *_event_ctx;
/**
* @brief fileserver event mutex, protects event cb and event ctx from concurrent access
*/
static mutex_t _event_mtx;
/**
* @brief Structure holding information about present options in a request
*/
@ -146,6 +161,26 @@ static void _calc_szx2(coap_pkt_t *pdu, size_t reserve, coap_block1_t *block2)
}
}
static inline void _event_file(gcoap_fileserver_event_t event, struct requestdata *request)
{
if (!IS_USED(MODULE_GCOAP_FILESERVER_CALLBACK)) {
return;
}
mutex_lock(&_event_mtx);
gcoap_fileserver_event_ctx_t ctx = {
.path = request->namebuf,
.user_ctx = _event_ctx,
};
gcoap_fileserver_event_handler_t cb = _event_cb;
mutex_unlock(&_event_mtx);
if (cb) {
cb(event, &ctx);
}
}
static ssize_t _get_file(coap_pkt_t *pdu, uint8_t *buf, size_t len,
struct requestdata *request)
{
@ -193,6 +228,10 @@ static ssize_t _get_file(coap_pkt_t *pdu, uint8_t *buf, size_t len,
goto late_err;
}
if (block2.blknum == 0) {
_event_file(GCOAP_FILESERVER_GET_FILE_START, request);
}
/* That'd only happen if the buffer is too small for even a 16-byte block,
* or if the above calculations were wrong.
*
@ -218,6 +257,10 @@ static ssize_t _get_file(coap_pkt_t *pdu, uint8_t *buf, size_t len,
read -= 1;
}
if (!more) {
_event_file(GCOAP_FILESERVER_GET_FILE_END, request);
}
return resp_len + read;
late_err:
@ -257,6 +300,8 @@ static ssize_t _put_file(coap_pkt_t *pdu, uint8_t *buf, size_t len,
ret = COAP_CODE_PRECONDITION_FAILED;
goto unlink_on_error;
}
_event_file(GCOAP_FILESERVER_PUT_FILE_START, request);
}
if (request->options.exists.if_match) {
stat_etag(&stat, &etag); /* Etag before write */
@ -316,6 +361,9 @@ static ssize_t _put_file(coap_pkt_t *pdu, uint8_t *buf, size_t len,
goto unlink_on_error;
}
}
_event_file(GCOAP_FILESERVER_PUT_FILE_END, request);
stat_etag(&stat, &etag); /* Etag after write */
gcoap_resp_init(pdu, buf, len, create ? COAP_CODE_CREATED : COAP_CODE_CHANGED);
coap_opt_add_opaque(pdu, COAP_OPT_ETAG, &etag, sizeof(etag));
@ -353,6 +401,9 @@ static ssize_t _delete_file(coap_pkt_t *pdu, uint8_t *buf, size_t len,
return gcoap_fileserver_error_handler(pdu, buf, len, COAP_CODE_PRECONDITION_FAILED);
}
}
_event_file(GCOAP_FILESERVER_DELETE_FILE, request);
if ((ret = vfs_unlink(request->namebuf)) < 0) {
return gcoap_fileserver_error_handler(pdu, buf, len, ret);
}
@ -650,4 +701,16 @@ error:
return gcoap_response(pdu, buf, len, errorcode);
}
#ifdef MODULE_GCOAP_FILESERVER_CALLBACK
void gcoap_fileserver_set_event_cb(gcoap_fileserver_event_handler_t cb, void *ctx)
{
mutex_lock(&_event_mtx);
_event_cb = cb;
_event_ctx = ctx;
mutex_unlock(&_event_mtx);
}
#endif
/** @} */