mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge #18414
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:
commit
d6f44f6206
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
|
||||
/** @} */
|
||||
|
Loading…
Reference in New Issue
Block a user