1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
5 * @file ConfigurationExample.ino
6 * @brief Reference for every user-configurable flag and constant.
8 * All defines must appear BEFORE the library include. Any that are omitted
9 * get their documented defaults. Illegal combinations (e.g. pool sizes that
10 * exceed MAX_CONNS) produce a #error message in the compiler output.
12 * ============================================================
13 * FEATURE FLAGS (set to 0 to strip from the build entirely)
14 * ============================================================
16 * DETWS_ENABLE_WEBSOCKET default 1
17 * WebSocket support: RFC 6455 framing, SHA-1 handshake via mbedTLS,
18 * base64 encode/decode. Pulls in websocket.h/cpp, sha1.cpp, base64.cpp.
19 * Set to 0 if your project only needs plain HTTP.
21 * DETWS_ENABLE_SSE default 1
22 * Server-Sent Events: keeps connections open and pushes text events.
23 * Pulls in sse.h/cpp. Set to 0 if you do not need server push.
25 * DETWS_ENABLE_MULTIPART default 1
26 * multipart/form-data body parser for file and field uploads.
27 * Pulls in multipart.h/cpp. Set to 0 for REST-only APIs.
29 * DETWS_ENABLE_FILE_SERVING default 1
30 * Static file serving via any Arduino FS (LittleFS, SPIFFS, SD).
31 * Pulls in FS.h and the serve_file() method. Set to 0 if you serve
32 * all responses programmatically.
34 * DETWS_ENABLE_AUTH default 1
35 * HTTP Basic Authentication per-route. Pulls in base64.cpp.
36 * Set to 0 if all routes are public.
38 * ============================================================
39 * CAPACITY CONSTANTS (affect static array sizes → RAM / flash)
40 * ============================================================
43 * Maximum simultaneous TCP connections. Each slot holds one TcpConn
44 * struct (id, state, pcb pointer, timestamp, RX_BUF_SIZE ring buffer).
45 * Constraint: MAX_WS_CONNS + MAX_SSE_CONNS <= MAX_CONNS.
48 * RX_BUF_SIZE default 1024
49 * Ring-buffer capacity in bytes per connection slot. Must be >=
50 * BODY_BUF_SIZE and >= FILE_CHUNK_SIZE. Larger values tolerate bursts
51 * of inbound data without applying TCP backpressure.
53 * MAX_HEADERS default 8
54 * Maximum HTTP headers stored per request. Headers beyond this limit
55 * are consumed but not stored (no error, no truncation of the key/value
56 * that was already stored).
58 * MAX_PATH_LEN default 64
59 * Maximum URL path length including the leading '/'. Requests whose
60 * path exceeds this receive 414 URI Too Long automatically.
63 * MAX_KEY_LEN default 24
64 * Maximum header field-name length (e.g. "Content-Type" = 12 chars).
65 * Keys that exceed this for a stored header slot trigger PARSE_ERROR.
68 * MAX_VAL_LEN default 48
69 * Maximum header field-value length. Values that exceed this are
70 * silently truncated — no protocol error. Increase if you expect long
71 * Authorization or Content-Type values.
73 * MAX_QUERY_LEN default 128
74 * Maximum raw query string length (everything after '?'). Overflow is
77 * MAX_QUERY_PARAMS default 8
78 * Maximum number of key=value pairs parsed from the query string.
79 * Extra pairs are silently ignored.
81 * QUERY_KEY_LEN default 24
82 * Maximum query-parameter key length.
84 * QUERY_VAL_LEN default 48
85 * Maximum query-parameter value length.
87 * BODY_BUF_SIZE default 256
88 * Maximum request body stored in HttpReq::body. Requests with a
89 * Content-Length larger than this receive 413 Payload Too Large
90 * before any body bytes are read.
91 * Constraint: BODY_BUF_SIZE <= RX_BUF_SIZE.
93 * MAX_ROUTES default 16
94 * Maximum simultaneously registered routes (on(), on_ws(), on_sse()).
95 * Registrations beyond this limit are silently ignored.
98 * ============================================================
99 * WEBSOCKET CONSTANTS (DETWS_ENABLE_WEBSOCKET must be 1)
100 * ============================================================
102 * MAX_WS_CONNS default 2
103 * Maximum simultaneous WebSocket connections. Each consumes one TCP
104 * slot from MAX_CONNS and one WsConn struct (id, state, WS_FRAME_SIZE
106 * Constraint: MAX_WS_CONNS + MAX_SSE_CONNS <= MAX_CONNS.
108 * WS_FRAME_SIZE default 512
109 * Maximum WebSocket frame payload in bytes. Frames larger than this
110 * are rejected with Close code 1009 (Message Too Big). Fragmented
111 * messages are not supported.
114 * ============================================================
115 * SSE CONSTANTS (DETWS_ENABLE_SSE must be 1)
116 * ============================================================
118 * MAX_SSE_CONNS default 2
119 * Maximum simultaneous SSE connections. Each consumes one TCP slot
120 * from MAX_CONNS and one SseConn struct.
121 * Constraint: MAX_WS_CONNS + MAX_SSE_CONNS <= MAX_CONNS.
123 * SSE_BUF_SIZE default 256
124 * Output buffer in bytes for one formatted SSE event
125 * ("event: ...\ndata: ...\nid: ...\n\n"). Events that would exceed
126 * this after formatting are not sent (sse_write returns false).
129 * ============================================================
130 * FILE SERVING CONSTANTS (DETWS_ENABLE_FILE_SERVING must be 1)
131 * ============================================================
133 * FILE_CHUNK_SIZE default 512
134 * Bytes read from the filesystem and passed to tcp_write() per chunk.
135 * Smaller values reduce peak stack usage; larger values improve
136 * throughput. Constraint: FILE_CHUNK_SIZE <= RX_BUF_SIZE.
138 * ============================================================
139 * AUTH CONSTANTS (DETWS_ENABLE_AUTH must be 1)
140 * ============================================================
142 * MAX_AUTH_LEN default 32
143 * Maximum username or password length including the null terminator.
144 * Credentials longer than this are rejected with 401.
147 * ============================================================
148 * MULTIPART CONSTANTS (DETWS_ENABLE_MULTIPART must be 1)
149 * ============================================================
151 * MAX_MULTIPART_PARTS default 4
152 * Maximum number of form parts parsed per request. Extra parts are
153 * silently ignored. Range: >= 1.
155 * MAX_BOUNDARY_LEN default 72
156 * Maximum MIME boundary length. RFC 2046 allows up to 70 characters;
157 * 72 adds two bytes of margin. Note: the actual boundary available is
158 * further constrained by MAX_VAL_LEN (the stored Content-Type value
159 * must fit within MAX_VAL_LEN including the "multipart/form-data;
160 * boundary=" prefix which is 30 chars).
162 * ============================================================
163 * RUNTIME CONFIGURATION (passed to server.begin())
164 * ============================================================
166 * WebServerConfig::conn_timeout_ms default 5000
167 * Milliseconds of inactivity before a connection is force-closed via
168 * tcp_abort(). Can live in flash (PROGMEM) or RAM.
170 * Flash (no RAM cost):
171 * const WebServerConfig cfg PROGMEM = { .conn_timeout_ms = 10000 };
173 * RAM (changeable at runtime):
174 * WebServerConfig cfg = { .conn_timeout_ms = 10000 };
176 * Pass nullptr (or omit) to use the built-in default of 5000 ms.
179// -------------------------------------------------------------------
180// Example: a low-footprint REST-only server — no WS, SSE, or file IO
181// -------------------------------------------------------------------
183#define DETWS_ENABLE_WEBSOCKET 0
184#define DETWS_ENABLE_SSE 0
185#define DETWS_ENABLE_MULTIPART 0
186#define DETWS_ENABLE_FILE_SERVING 0
187#define DETWS_ENABLE_AUTH 0
189// Enable diagnostic endpoint (disable before production deployment)
190#define DETWS_ENABLE_DIAG 1
192// Tighten capacity to match a small REST API
194#define EVT_QUEUE_DEPTH 8 // >= MAX_CONNS * 4
195#define RX_BUF_SIZE 512
196#define BODY_BUF_SIZE 128
199#define MAX_PATH_LEN 48
200#define MAX_VAL_LEN 64
202#include "DeterministicESPAsyncWebServer.h"
203#include "network_drivers/physical.h"
206static const char *SSID = "YOUR_SSID";
207static const char *PASSWORD = "YOUR_PASSWORD";
209// Runtime config — 10 s timeout, stored in flash
210static const WebServerConfig cfg PROGMEM = { .conn_timeout_ms = 10000 };
214void handle_status(uint8_t slot_id, HttpReq *req)
216 server.send(slot_id, 200, "application/json", "{\"status\":\"ok\"}");
219void handle_not_found(uint8_t slot_id, HttpReq *req)
221 server.send(slot_id, 404, "text/plain", "Not found");
226 Serial.begin(115200);
228 // heap_needed() returns 0 and heap_available() returns true — the event
229 // queue is statically allocated in BSS so begin() makes no heap allocation.
230 // These calls are retained here only to show the API exists.
232 init_wifi_physical(SSID, PASSWORD);
233 Serial.print("Connecting");
234 while (!wifi_ready()) { delay(250); Serial.print('.'); }
235 Serial.print("\nIP: ");
236 Serial.println(WiFi.localIP());
238 server.on("/status", HTTP_GET, handle_status);
240 // Diagnostic route — remove or protect with auth in production
241 server.on("/diag", HTTP_GET, [](uint8_t id, HttpReq *) { server.diag(id); });
243 server.on_not_found(handle_not_found);
245 int32_t result = server.begin(80, &cfg);
248 Serial.printf("begin() failed — need %d contiguous heap bytes\n", -result);
251 Serial.println("Server ready on port 80");