1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:12:57 +01:00

gcoap/fileserver: add event callbacks

This commit is contained in:
Benjamin Valentin 2022-08-05 22:07:51 +02:00
parent 004ac82af5
commit 47295cc929
3 changed files with 109 additions and 0 deletions

View File

@ -67,6 +67,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 */
@ -310,6 +355,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));
@ -347,6 +395,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);
}
@ -644,4 +695,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
/** @} */