Berry 'webserver.remove_route' to revert 'webserver.on' (#23452)

This commit is contained in:
s-hadinger 2025-05-20 23:07:05 +02:00 committed by GitHub
parent 7ce3ba376c
commit 40bc108ba1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 64 additions and 4 deletions

View File

@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
- Provide serial upload port from VSC to PIO (#23436)
- Berry support for `sortedmap` (#23441)
- Berry `introspect.module` option to not cache module entry
- Berry `webserver.remove_route` to revert `webserver.on`
### Breaking Changed

View File

@ -14,6 +14,7 @@
extern int w_webserver_member(bvm *vm);
extern int w_webserver_on(bvm *vm);
extern int w_webserver_remove_route(bvm *vm);
extern int w_webserver_state(bvm *vm);
extern int w_webserver_check_privileged_access(bvm *vm);
@ -95,11 +96,24 @@ static const berry_webserver_cb_t berry_callback_array[WEBSERVER_REQ_HANDLER_HOO
// -1 if no more available
berry_webserver_cb_t be_webserver_allocate_hook(bvm *vm, int32_t slot, bvalue *f) {
if (slot < 0 || slot >= WEBSERVER_REQ_HANDLER_HOOK_MAX) return NULL; // invalid call, avoid a crash
if (be_isgcobj(f)) {
be_gc_fix_set(vm, f->v.gc, btrue); // mark the function as non-gc
}
be_webserver_cb_hooks[slot].vm = vm;
be_webserver_cb_hooks[slot].f = *f;
return berry_callback_array[slot];
}
bbool be_webserver_deallocate_hook(bvm *vm, int32_t slot) {
if (slot < 0 || slot >= WEBSERVER_REQ_HANDLER_HOOK_MAX) return bfalse; // invalid call, avoid a crash
bvalue f = be_webserver_cb_hooks[slot].f;
if (be_isgcobj(&f)) {
be_gc_fix_set(vm, f.v.gc, bfalse); // remove the marker for non-gc
}
var_setnil(&be_webserver_cb_hooks[slot].f);
return btrue;
}
/*********************************************************************************************\
* `be_webserver_cb_deinit`:
* Clean any callback for this VM
@ -144,6 +158,7 @@ module webserver (scope: global) {
member, func(w_webserver_member)
on, func(w_webserver_on)
remove_route, func(w_webserver_remove_route)
state, func(w_webserver_state)
check_privileged_access, func(w_webserver_check_privileged_access)

View File

@ -646,6 +646,13 @@ void WebServer_on(const char * prefix, void (*func)(void), uint8_t method = HTTP
#endif // ESP32
}
#ifdef ESP32
void WebServer_removeRoute(const char * prefix, uint8_t method = HTTP_ANY) {
if (Webserver == nullptr) { return; }
Webserver->removeRoute(prefix, (HTTPMethod) method);
}
#endif // ESP32
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
// Always listens to all interfaces, so we don't need an IP address anymore

View File

@ -78,7 +78,8 @@ static uint8_t be_webserver_method[WEBSERVER_REQ_HANDLER_HOOK_MAX];
extern "C" {
typedef void (*berry_webserver_cb_t)(void);
extern berry_webserver_cb_t be_webserver_allocate_hook(bvm *vm, int32_t num, bvalue *f);
// Berry: `webserver.on(prefix:string, callback:closure) -> nil`
extern bbool be_webserver_deallocate_hook(bvm *vm, int32_t slot);
// Berry: `webserver.on(prefix:string, callback:closure [, method:int]) -> nil`
//
// WARNING - this should be called only when receiving `web_add_handler` event.
// If called before the WebServer is set up and Wifi on, it will crash.
@ -119,9 +120,6 @@ extern "C" {
// AddLog(LOG_LEVEL_INFO, ">>>: slot found = %i", slot);
bvalue *v = be_indexof(vm, 2);
if (be_isgcobj(v)) {
be_gc_fix_set(vm, v->v.gc, btrue); // mark the function as non-gc
}
berry_webserver_cb_t cb = be_webserver_allocate_hook(vm, slot, v);
if (cb == NULL) { be_raise(vm, kInternalError, nullptr); }
be_webserver_prefix[slot] = prefix;
@ -133,6 +131,45 @@ extern "C" {
be_raise(vm, kTypeError, nullptr);
}
// Berry: `webserver.remove_handler(prefix:string [, method:int]) -> nil`
//
// Remove a handler already added with `webserver.on()`
// Does nothing if the handler does not exist or was already removed
//
int32_t w_webserver_remove_route(struct bvm *vm);
int32_t w_webserver_remove_route(struct bvm *vm) {
int32_t argc = be_top(vm); // Get the number of arguments
bbool good = bfalse;
if (argc >= 1 && be_isstring(vm, 1) && (argc < 2 || be_isint(vm, 2)) ) { // optional second argument must be int
uint8_t method = HTTP_ANY; // default method if not specified
const char * prefix = be_tostring(vm, 1);
if (argc >= 2) {
method = be_toint(vm, 2);
}
// find the slot that matches the prefix/method
int32_t slot;
for (slot = 0; slot < WEBSERVER_REQ_HANDLER_HOOK_MAX; slot++) {
if (be_webserver_prefix[slot] == prefix && be_webserver_method[slot] == method) {
break;
}
}
if (slot < WEBSERVER_REQ_HANDLER_HOOK_MAX) {
// remove from handler
WebServer_removeRoute(be_webserver_prefix[slot].c_str(), be_webserver_method[slot]);
// mark slot as free
be_webserver_prefix[slot] = "";
// Deallocate cb slot
be_webserver_deallocate_hook(vm, slot);
good = btrue;
}
be_pushbool(vm, good);
be_return(vm); // return, all good
}
be_raise(vm, kTypeError, nullptr);
}
// Berry: `webserver.state() -> int`
//
int32_t w_webserver_state(struct bvm *vm);