svelteesp32 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ import type { TemplateData } from './cppCode';
2
+ export declare const genAsyncCpp: (d: TemplateData) => string;
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.genAsyncCpp = void 0;
4
+ const cppCode_1 = require("./cppCode");
5
+ const genAsyncHandlerBody = (d, source, path) => {
6
+ const lines = [];
7
+ const etagCheck = (0, cppCode_1.sw)(d.etag, {
8
+ always: [
9
+ ` const AsyncWebHeader* h = request->getHeader("If-None-Match");`,
10
+ ` if (h && h->value().equals(etag_${source.dataname})) {`,
11
+ ` ${d.definePrefix}_onFileServed("${path}", 304);`,
12
+ ` request->send(304);`,
13
+ ` return;`,
14
+ ` }`
15
+ ].join('\n'),
16
+ compiler: [
17
+ ` #ifdef ${d.definePrefix}_ENABLE_ETAG`,
18
+ ` const AsyncWebHeader* h = request->getHeader("If-None-Match");`,
19
+ ` if (h && h->value().equals(etag_${source.dataname})) {`,
20
+ ` ${d.definePrefix}_onFileServed("${path}", 304);`,
21
+ ` request->send(304);`,
22
+ ` return;`,
23
+ ` }`,
24
+ ` #endif`
25
+ ].join('\n')
26
+ });
27
+ if (etagCheck)
28
+ lines.push(etagCheck);
29
+ lines.push((0, cppCode_1.sw)(d.gzip, {
30
+ always: [
31
+ ` AsyncWebServerResponse *response = request->beginResponse(200, "${source.mime}", datagzip_${source.dataname}, ${source.lengthGzip});`,
32
+ ...(source.isGzip ? [` response->addHeader("Content-Encoding", "gzip");`] : [])
33
+ ].join('\n'),
34
+ never: ` AsyncWebServerResponse *response = request->beginResponse(200, "${source.mime}", data_${source.dataname}, ${source.length});`,
35
+ compiler: [
36
+ ` #ifdef ${d.definePrefix}_ENABLE_GZIP`,
37
+ ` AsyncWebServerResponse *response = request->beginResponse(200, "${source.mime}", datagzip_${source.dataname}, ${source.lengthGzip});`,
38
+ ...(source.isGzip ? [` response->addHeader("Content-Encoding", "gzip");`] : []),
39
+ ` #else`,
40
+ ` AsyncWebServerResponse *response = request->beginResponse(200, "${source.mime}", data_${source.dataname}, ${source.length});`,
41
+ ` #endif`
42
+ ].join('\n')
43
+ }));
44
+ const cacheHeaders = (0, cppCode_1.sw)(d.etag, {
45
+ always: [
46
+ ` response->addHeader("Cache-Control", "${(0, cppCode_1.cacheCtrl)(source)}");`,
47
+ ` response->addHeader("ETag", etag_${source.dataname});`
48
+ ].join('\n'),
49
+ compiler: [
50
+ ` #ifdef ${d.definePrefix}_ENABLE_ETAG`,
51
+ ` response->addHeader("Cache-Control", "${(0, cppCode_1.cacheCtrl)(source)}");`,
52
+ ` response->addHeader("ETag", etag_${source.dataname});`,
53
+ ` #endif`
54
+ ].join('\n')
55
+ });
56
+ if (cacheHeaders)
57
+ lines.push(cacheHeaders);
58
+ lines.push(` ${d.definePrefix}_onFileServed("${path}", 200);`, ` request->send(response);`);
59
+ return lines.join('\n');
60
+ };
61
+ const genAsyncCpp = (d) => {
62
+ const lines = [
63
+ `//engine: ESPAsyncWebServer`,
64
+ `//config: ${d.config}`,
65
+ ...(d.created ? [`//created: ${d.now}`] : []),
66
+ '//',
67
+ (0, cppCode_1.genCommonHeader)(d),
68
+ '//',
69
+ '#include <Arduino.h>',
70
+ '#include <ESPAsyncWebServer.h>',
71
+ '//',
72
+ (0, cppCode_1.genDataArrays)(d, true),
73
+ '//',
74
+ (0, cppCode_1.genEtagArrays)(d),
75
+ '//',
76
+ (0, cppCode_1.genManifest)(d),
77
+ '//',
78
+ (0, cppCode_1.genHook)(d),
79
+ '//',
80
+ '// Http Handlers',
81
+ `void ${d.methodName}(AsyncWebServer * server) {`
82
+ ];
83
+ for (const source of d.sources) {
84
+ const path = `${d.basePath}/${source.filename}`;
85
+ const defaultPath = d.basePath || '/';
86
+ lines.push('//', `// ${source.filename}`, ` server->on("${path}", HTTP_GET, [](AsyncWebServerRequest * request) {`, genAsyncHandlerBody(d, source, path), ` });`);
87
+ if (source.isDefault)
88
+ lines.push(` server->on("${defaultPath}", HTTP_GET, [](AsyncWebServerRequest * request) {`, genAsyncHandlerBody(d, source, defaultPath), ` });`);
89
+ }
90
+ if (d.spa && d.spaSource) {
91
+ const source = d.spaSource;
92
+ const path = `${d.basePath}/${source.filename}`;
93
+ lines.push('//', `// SPA catch-all: unmatched routes serve ${source.filename}`, ` server->onNotFound([](AsyncWebServerRequest * request) {`, ` if (request->method() != HTTP_GET) { request->send(404); return; }`);
94
+ if (d.basePath)
95
+ lines.push(` if (!request->url().startsWith("${d.basePath}/") && request->url() != "${d.basePath}") { request->send(404); return; }`);
96
+ lines.push(genAsyncHandlerBody(d, source, path), ` });`);
97
+ }
98
+ lines.push('}');
99
+ return lines.join('\n');
100
+ };
101
+ exports.genAsyncCpp = genAsyncCpp;
@@ -1 +1,2 @@
1
- export declare const espidfTemplate = "\n//engine: espidf\n//config: {{{config}}}\n{{#if created }}\n//created: {{now}}\n{{/if}}\n//\n\n{{#switch etag}}\n{{#case \"always\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"never\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n{{#switch gzip}}\n{{#case \"always\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON\n#endif\n{{/case}}\n{{#case \"never\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF\n#endif\n{{/case}}\n{{/switch}}\n\n//\n{{#if version }}\n#define {{definePrefix}}_VERSION \"{{version}}\"\n{{/if}}\n#define {{definePrefix}}_COUNT {{fileCount}}\n#define {{definePrefix}}_SIZE {{fileSize}}\n#define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}\n\n//\n{{#each sources}}\n#define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}\n{{/each}}\n\n//\n{{#each filesByExtension}}\n#define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}\n{{/each}}\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include <esp_err.h>\n#include <esp_http_server.h>\n\n//\n{{#switch gzip}}\n{{#case \"always\"}}\n {{#each sources}}\nstatic const unsigned char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n{{/case}}\n{{#case \"never\"}}\n {{#each sources}}\nstatic const unsigned char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_GZIP\n {{#each sources}}\nstatic const unsigned char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };\n {{/each}}\n#else\n {{#each sources}}\nstatic const unsigned char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };\n {{/each}}\n#endif \n{{/case}}\n{{/switch}}\n\n//\n{{#switch etag}}\n{{#case \"always\"}}\n {{#each sources}}\nstatic const char etag_{{this.dataname}}[] = \"{{this.sha256}}\";\n {{/each}}\n{{/case}}\n{{#case \"never\"}}\n{{/case}}\n{{#case \"compiler\"}}\n#ifdef {{definePrefix}}_ENABLE_ETAG\n {{#each sources}}\nstatic const char etag_{{this.dataname}}[] = \"{{this.sha256}}\";\n {{/each}}\n#endif\n{{/case}}\n{{/switch}}\n\n// File manifest struct (C-compatible typedef)\ntypedef struct {\n const char* path;\n uint32_t size;\n uint32_t gzipSize;\n const char* etag;\n const char* contentType;\n} {{definePrefix}}_FileInfo;\n\n// File manifest array\nstatic const {{definePrefix}}_FileInfo {{definePrefix}}_FILES[] = {\n{{#each sources}}\n { \"{{../basePath}}/{{this.filename}}\", {{this.length}}, {{this.gzipSizeForManifest}}, {{this.etagForManifest}}, \"{{this.mime}}\" },\n{{/each}}\n};\nstatic const size_t {{definePrefix}}_FILE_COUNT = sizeof({{definePrefix}}_FILES) / sizeof({{definePrefix}}_FILES[0]);\n\n// File served hook - override with your own implementation\n__attribute__((weak)) void {{definePrefix}}_onFileServed(const char* path, int statusCode) {}\n\n{{#each sources}}\n\nstatic esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)\n{\n{{#switch ../etag}}\n{{#case \"always\"}}\n size_t hdr_len = httpd_req_get_hdr_value_len(req, \"If-None-Match\");\n if (hdr_len > 0) {\n char* hdr_value = malloc(hdr_len + 1);\n if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }\n if (httpd_req_get_hdr_value_str(req, \"If-None-Match\", hdr_value, hdr_len + 1) == ESP_OK) {\n if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {\n free(hdr_value);\n httpd_resp_set_status(req, \"304 Not Modified\");\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 304);\n httpd_resp_send(req, NULL, 0);\n return ESP_OK;\n }\n }\n free(hdr_value);\n }\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_ETAG\n size_t hdr_len = httpd_req_get_hdr_value_len(req, \"If-None-Match\");\n if (hdr_len > 0) {\n char* hdr_value = malloc(hdr_len + 1);\n if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }\n if (httpd_req_get_hdr_value_str(req, \"If-None-Match\", hdr_value, hdr_len + 1) == ESP_OK) {\n if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {\n free(hdr_value);\n httpd_resp_set_status(req, \"304 Not Modified\");\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 304);\n httpd_resp_send(req, NULL, 0);\n return ESP_OK;\n }\n }\n free(hdr_value);\n }\n #endif\n{{/case}}\n{{/switch}}\n httpd_resp_set_type(req, \"{{this.mime}}\");\n{{#switch ../gzip}}\n{{#case \"always\"}}\n{{#if this.isGzip}}\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n{{/if}}\n{{/case}}\n{{#case \"compiler\"}}\n {{#if this.isGzip}}\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_set_hdr(req, \"Content-Encoding\", \"gzip\");\n #endif \n {{/if}}\n{{/case}}\n{{/switch}}\n\n{{#switch ../etag}}\n{{#case \"always\"}}\n{{#this.cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/this.cacheTime}}\n{{^this.cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/this.cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n{{/case}}\n{{#case \"compiler\"}}\n #ifdef {{../definePrefix}}_ENABLE_ETAG\n{{#this.cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"max-age={{value}}\");\n{{/this.cacheTime}}\n{{^this.cacheTime}}\n httpd_resp_set_hdr(req, \"Cache-Control\", \"no-cache\");\n{{/this.cacheTime}}\n httpd_resp_set_hdr(req, \"ETag\", etag_{{this.dataname}});\n #endif \n{{/case}}\n{{/switch}}\n\n{{#switch ../gzip}}\n{{#case \"always\"}}\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 200);\n httpd_resp_send(req, (const char *)datagzip_{{this.dataname}}, {{this.lengthGzip}});\n{{/case}}\n{{#case \"never\"}}\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 200);\n httpd_resp_send(req, (const char *)data_{{this.dataname}}, {{this.length}});\n{{/case}}\n{{#case \"compiler\"}}\n {{../definePrefix}}_onFileServed(\"{{../basePath}}/{{this.filename}}\", 200);\n #ifdef {{../definePrefix}}_ENABLE_GZIP\n httpd_resp_send(req, (const char *)datagzip_{{this.dataname}}, {{this.lengthGzip}});\n #else\n httpd_resp_send(req, (const char *)data_{{this.dataname}}, {{this.length}});\n #endif\n{{/case}}\n{{/switch}}\n return ESP_OK;\n}\n\n{{#if this.isDefault}}\nstatic const httpd_uri_t route_def_{{this.datanameUpperCase}} = {\n .uri = \"{{#if ../basePath}}{{../basePath}}{{else}}/{{/if}}\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n{{/if}}\n\nstatic const httpd_uri_t route_{{this.datanameUpperCase}} = {\n .uri = \"{{../basePath}}/{{this.filename}}\",\n .method = HTTP_GET,\n .handler = file_handler_{{this.datanameUpperCase}},\n};\n\n{{/each}}\n\n{{#if spa}}\n{{#with spaSource}}\nstatic esp_err_t spa_handler_{{this.datanameUpperCase}}(httpd_req_t *req, httpd_err_code_t err) {\n{{#if ../basePath}}\n const char* prefix = \"{{../basePath}}/\";\n if (strncmp(req->uri, prefix, strlen(prefix)) != 0 && strcmp(req->uri, \"{{../basePath}}\") != 0) {\n httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, \"Not found\");\n return ESP_FAIL;\n }\n{{/if}}\n return file_handler_{{this.datanameUpperCase}}(req);\n}\n{{/with}}\n{{/if}}\n\n\nstatic inline void {{methodName}}(httpd_handle_t server) {\n{{#each sources}}\n{{#if this.isDefault}}\n httpd_register_uri_handler(server, &route_def_{{this.datanameUpperCase}});\n{{/if}}\n httpd_register_uri_handler(server, &route_{{this.datanameUpperCase}});\n{{/each}}\n{{#if spa}}\n{{#with spaSource}}\n httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, spa_handler_{{this.datanameUpperCase}});\n{{/with}}\n{{/if}}\n\n}";
1
+ import type { TemplateData } from './cppCode';
2
+ export declare const genEspIdfCpp: (d: TemplateData) => string;
@@ -1,272 +1,178 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.espidfTemplate = void 0;
4
- exports.espidfTemplate = `
5
- //engine: espidf
6
- //config: {{{config}}}
7
- {{#if created }}
8
- //created: {{now}}
9
- {{/if}}
10
- //
11
-
12
- {{#switch etag}}
13
- {{#case "always"}}
14
- #ifdef {{definePrefix}}_ENABLE_ETAG
15
- #warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON
16
- #endif
17
- {{/case}}
18
- {{#case "never"}}
19
- #ifdef {{definePrefix}}_ENABLE_ETAG
20
- #warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF
21
- #endif
22
- {{/case}}
23
- {{/switch}}
24
-
25
- {{#switch gzip}}
26
- {{#case "always"}}
27
- #ifdef {{definePrefix}}_ENABLE_GZIP
28
- #warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON
29
- #endif
30
- {{/case}}
31
- {{#case "never"}}
32
- #ifdef {{definePrefix}}_ENABLE_GZIP
33
- #warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF
34
- #endif
35
- {{/case}}
36
- {{/switch}}
37
-
38
- //
39
- {{#if version }}
40
- #define {{definePrefix}}_VERSION "{{version}}"
41
- {{/if}}
42
- #define {{definePrefix}}_COUNT {{fileCount}}
43
- #define {{definePrefix}}_SIZE {{fileSize}}
44
- #define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}
45
-
46
- //
47
- {{#each sources}}
48
- #define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}
49
- {{/each}}
50
-
51
- //
52
- {{#each filesByExtension}}
53
- #define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}
54
- {{/each}}
55
-
56
- #include <stdint.h>
57
- #include <string.h>
58
- #include <stdlib.h>
59
- #include <esp_err.h>
60
- #include <esp_http_server.h>
61
-
62
- //
63
- {{#switch gzip}}
64
- {{#case "always"}}
65
- {{#each sources}}
66
- static const unsigned char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
67
- {{/each}}
68
- {{/case}}
69
- {{#case "never"}}
70
- {{#each sources}}
71
- static const unsigned char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
72
- {{/each}}
73
- {{/case}}
74
- {{#case "compiler"}}
75
- #ifdef {{definePrefix}}_ENABLE_GZIP
76
- {{#each sources}}
77
- static const unsigned char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
78
- {{/each}}
79
- #else
80
- {{#each sources}}
81
- static const unsigned char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
82
- {{/each}}
83
- #endif
84
- {{/case}}
85
- {{/switch}}
86
-
87
- //
88
- {{#switch etag}}
89
- {{#case "always"}}
90
- {{#each sources}}
91
- static const char etag_{{this.dataname}}[] = "{{this.sha256}}";
92
- {{/each}}
93
- {{/case}}
94
- {{#case "never"}}
95
- {{/case}}
96
- {{#case "compiler"}}
97
- #ifdef {{definePrefix}}_ENABLE_ETAG
98
- {{#each sources}}
99
- static const char etag_{{this.dataname}}[] = "{{this.sha256}}";
100
- {{/each}}
101
- #endif
102
- {{/case}}
103
- {{/switch}}
104
-
105
- // File manifest struct (C-compatible typedef)
106
- typedef struct {
107
- const char* path;
108
- uint32_t size;
109
- uint32_t gzipSize;
110
- const char* etag;
111
- const char* contentType;
112
- } {{definePrefix}}_FileInfo;
113
-
114
- // File manifest array
115
- static const {{definePrefix}}_FileInfo {{definePrefix}}_FILES[] = {
116
- {{#each sources}}
117
- { "{{../basePath}}/{{this.filename}}", {{this.length}}, {{this.gzipSizeForManifest}}, {{this.etagForManifest}}, "{{this.mime}}" },
118
- {{/each}}
3
+ exports.genEspIdfCpp = void 0;
4
+ const cppCode_1 = require("./cppCode");
5
+ const genEspIdfFileHandler = (d, source) => {
6
+ const path = `${d.basePath}/${source.filename}`;
7
+ const lines = [`static esp_err_t file_handler_${source.datanameUpperCase} (httpd_req_t *req)`, '{'];
8
+ const etagCheck = (0, cppCode_1.sw)(d.etag, {
9
+ always: [
10
+ ` size_t hdr_len = httpd_req_get_hdr_value_len(req, "If-None-Match");`,
11
+ ` if (hdr_len > 0) {`,
12
+ ` char* hdr_value = malloc(hdr_len + 1);`,
13
+ ` if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }`,
14
+ ` if (httpd_req_get_hdr_value_str(req, "If-None-Match", hdr_value, hdr_len + 1) == ESP_OK) {`,
15
+ ` if (strcmp(hdr_value, etag_${source.dataname}) == 0) {`,
16
+ ` free(hdr_value);`,
17
+ ` httpd_resp_set_status(req, "304 Not Modified");`,
18
+ ` ${d.definePrefix}_onFileServed("${path}", 304);`,
19
+ ` httpd_resp_send(req, NULL, 0);`,
20
+ ` return ESP_OK;`,
21
+ ` }`,
22
+ ` }`,
23
+ ` free(hdr_value);`,
24
+ ` }`
25
+ ].join('\n'),
26
+ compiler: [
27
+ ` #ifdef ${d.definePrefix}_ENABLE_ETAG`,
28
+ ` size_t hdr_len = httpd_req_get_hdr_value_len(req, "If-None-Match");`,
29
+ ` if (hdr_len > 0) {`,
30
+ ` char* hdr_value = malloc(hdr_len + 1);`,
31
+ ` if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }`,
32
+ ` if (httpd_req_get_hdr_value_str(req, "If-None-Match", hdr_value, hdr_len + 1) == ESP_OK) {`,
33
+ ` if (strcmp(hdr_value, etag_${source.dataname}) == 0) {`,
34
+ ` free(hdr_value);`,
35
+ ` httpd_resp_set_status(req, "304 Not Modified");`,
36
+ ` ${d.definePrefix}_onFileServed("${path}", 304);`,
37
+ ` httpd_resp_send(req, NULL, 0);`,
38
+ ` return ESP_OK;`,
39
+ ` }`,
40
+ ` }`,
41
+ ` free(hdr_value);`,
42
+ ` }`,
43
+ ` #endif`
44
+ ].join('\n')
45
+ });
46
+ if (etagCheck)
47
+ lines.push(etagCheck);
48
+ lines.push(` httpd_resp_set_type(req, "${source.mime}");`);
49
+ const gzipEncoding = (0, cppCode_1.sw)(d.gzip, {
50
+ always: source.isGzip ? ` httpd_resp_set_hdr(req, "Content-Encoding", "gzip");` : '',
51
+ compiler: source.isGzip
52
+ ? [
53
+ ` #ifdef ${d.definePrefix}_ENABLE_GZIP`,
54
+ ` httpd_resp_set_hdr(req, "Content-Encoding", "gzip");`,
55
+ ` #endif`
56
+ ].join('\n')
57
+ : ''
58
+ });
59
+ if (gzipEncoding)
60
+ lines.push(gzipEncoding);
61
+ const cacheHeaders = (0, cppCode_1.sw)(d.etag, {
62
+ always: [
63
+ ` httpd_resp_set_hdr(req, "Cache-Control", "${(0, cppCode_1.cacheCtrl)(source)}");`,
64
+ ` httpd_resp_set_hdr(req, "ETag", etag_${source.dataname});`
65
+ ].join('\n'),
66
+ compiler: [
67
+ ` #ifdef ${d.definePrefix}_ENABLE_ETAG`,
68
+ ` httpd_resp_set_hdr(req, "Cache-Control", "${(0, cppCode_1.cacheCtrl)(source)}");`,
69
+ ` httpd_resp_set_hdr(req, "ETag", etag_${source.dataname});`,
70
+ ` #endif`
71
+ ].join('\n')
72
+ });
73
+ if (cacheHeaders)
74
+ lines.push(cacheHeaders);
75
+ lines.push((0, cppCode_1.sw)(d.gzip, {
76
+ always: [
77
+ ` ${d.definePrefix}_onFileServed("${path}", 200);`,
78
+ ` httpd_resp_send(req, (const char *)datagzip_${source.dataname}, ${source.lengthGzip});`
79
+ ].join('\n'),
80
+ never: [
81
+ ` ${d.definePrefix}_onFileServed("${path}", 200);`,
82
+ ` httpd_resp_send(req, (const char *)data_${source.dataname}, ${source.length});`
83
+ ].join('\n'),
84
+ compiler: [
85
+ ` ${d.definePrefix}_onFileServed("${path}", 200);`,
86
+ ` #ifdef ${d.definePrefix}_ENABLE_GZIP`,
87
+ ` httpd_resp_send(req, (const char *)datagzip_${source.dataname}, ${source.lengthGzip});`,
88
+ ` #else`,
89
+ ` httpd_resp_send(req, (const char *)data_${source.dataname}, ${source.length});`,
90
+ ` #endif`
91
+ ].join('\n')
92
+ }), ` return ESP_OK;`, `}`);
93
+ if (source.isDefault) {
94
+ const defaultUri = d.basePath || '/';
95
+ lines.push(`static const httpd_uri_t route_def_${source.datanameUpperCase} = {`, ` .uri = "${defaultUri}",`, ` .method = HTTP_GET,`, ` .handler = file_handler_${source.datanameUpperCase},`, `};`);
96
+ }
97
+ lines.push(`static const httpd_uri_t route_${source.datanameUpperCase} = {`, ` .uri = "${path}",`, ` .method = HTTP_GET,`, ` .handler = file_handler_${source.datanameUpperCase},`, `};`);
98
+ return lines.join('\n');
119
99
  };
120
- static const size_t {{definePrefix}}_FILE_COUNT = sizeof({{definePrefix}}_FILES) / sizeof({{definePrefix}}_FILES[0]);
121
-
122
- // File served hook - override with your own implementation
123
- __attribute__((weak)) void {{definePrefix}}_onFileServed(const char* path, int statusCode) {}
124
-
125
- {{#each sources}}
126
-
127
- static esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)
128
- {
129
- {{#switch ../etag}}
130
- {{#case "always"}}
131
- size_t hdr_len = httpd_req_get_hdr_value_len(req, "If-None-Match");
132
- if (hdr_len > 0) {
133
- char* hdr_value = malloc(hdr_len + 1);
134
- if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }
135
- if (httpd_req_get_hdr_value_str(req, "If-None-Match", hdr_value, hdr_len + 1) == ESP_OK) {
136
- if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {
137
- free(hdr_value);
138
- httpd_resp_set_status(req, "304 Not Modified");
139
- {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 304);
140
- httpd_resp_send(req, NULL, 0);
141
- return ESP_OK;
142
- }
143
- }
144
- free(hdr_value);
100
+ const genEspIdfCpp = (d) => {
101
+ const lines = [
102
+ `//engine: espidf`,
103
+ `//config: ${d.config}`,
104
+ ...(d.created ? [`//created: ${d.now}`] : []),
105
+ '//'
106
+ ];
107
+ const etagWarn = (0, cppCode_1.sw)(d.etag, {
108
+ always: [
109
+ `#ifdef ${d.definePrefix}_ENABLE_ETAG`,
110
+ `#warning ${d.definePrefix}_ENABLE_ETAG has no effect because it is permanently switched ON`,
111
+ `#endif`
112
+ ].join('\n'),
113
+ never: [
114
+ `#ifdef ${d.definePrefix}_ENABLE_ETAG`,
115
+ `#warning ${d.definePrefix}_ENABLE_ETAG has no effect because it is permanently switched OFF`,
116
+ `#endif`
117
+ ].join('\n')
118
+ });
119
+ if (etagWarn)
120
+ lines.push(etagWarn);
121
+ const gzipWarn = (0, cppCode_1.sw)(d.gzip, {
122
+ always: [
123
+ `#ifdef ${d.definePrefix}_ENABLE_GZIP`,
124
+ `#warning ${d.definePrefix}_ENABLE_GZIP has no effect because it is permanently switched ON`,
125
+ `#endif`
126
+ ].join('\n'),
127
+ never: [
128
+ `#ifdef ${d.definePrefix}_ENABLE_GZIP`,
129
+ `#warning ${d.definePrefix}_ENABLE_GZIP has no effect because it is permanently switched OFF`,
130
+ `#endif`
131
+ ].join('\n')
132
+ });
133
+ if (gzipWarn)
134
+ lines.push(gzipWarn);
135
+ lines.push('//');
136
+ if (d.version)
137
+ lines.push(`#define ${d.definePrefix}_VERSION "${d.version}"`);
138
+ lines.push(`#define ${d.definePrefix}_COUNT ${d.fileCount}`, `#define ${d.definePrefix}_SIZE ${d.fileSize}`, `#define ${d.definePrefix}_SIZE_GZIP ${d.fileGzipSize}`, '//', ...d.sources.map((s) => `#define ${d.definePrefix}_FILE_${s.datanameUpperCase}`), '//', ...d.filesByExtension.map((g) => `#define ${d.definePrefix}_${g.extension}_FILES ${g.count}`), '#include <stdint.h>', '#include <string.h>', '#include <stdlib.h>', '#include <esp_err.h>', '#include <esp_http_server.h>', '//');
139
+ const gzipArrays = d.sources
140
+ .map((s) => `static const unsigned char datagzip_${s.dataname}[${s.lengthGzip}] = { ${s.bytesGzip} };`)
141
+ .join('\n');
142
+ const plainArrays = d.sources
143
+ .map((s) => `static const unsigned char data_${s.dataname}[${s.length}] = { ${s.bytes} };`)
144
+ .join('\n');
145
+ lines.push((0, cppCode_1.sw)(d.gzip, {
146
+ always: gzipArrays,
147
+ never: plainArrays,
148
+ compiler: [`#ifdef ${d.definePrefix}_ENABLE_GZIP`, gzipArrays, '#else', plainArrays, '#endif'].join('\n')
149
+ }), '//');
150
+ const etagItems = d.sources.map((s) => `static const char etag_${s.dataname}[] = "${s.sha256}";`).join('\n');
151
+ const etagBlock = (0, cppCode_1.sw)(d.etag, {
152
+ always: etagItems,
153
+ compiler: [`#ifdef ${d.definePrefix}_ENABLE_ETAG`, etagItems, '#endif'].join('\n')
154
+ });
155
+ if (etagBlock)
156
+ lines.push(etagBlock);
157
+ lines.push(`// File manifest struct (C-compatible typedef)`, `typedef struct {`, ` const char* path;`, ` uint32_t size;`, ` uint32_t gzipSize;`, ` const char* etag;`, ` const char* contentType;`, `} ${d.definePrefix}_FileInfo;`, `// File manifest array`, `static const ${d.definePrefix}_FileInfo ${d.definePrefix}_FILES[] = {`, ...d.sources.map((s) => ` { "${d.basePath}/${s.filename}", ${s.length}, ${s.gzipSizeForManifest}, ${s.etagForManifest}, "${s.mime}" },`), `};`, `static const size_t ${d.definePrefix}_FILE_COUNT = sizeof(${d.definePrefix}_FILES) / sizeof(${d.definePrefix}_FILES[0]);`, `// File served hook - override with your own implementation`, `__attribute__((weak)) void ${d.definePrefix}_onFileServed(const char* path, int statusCode) {}`);
158
+ for (const source of d.sources)
159
+ lines.push(genEspIdfFileHandler(d, source));
160
+ if (d.spa && d.spaSource) {
161
+ const source = d.spaSource;
162
+ lines.push(`static esp_err_t spa_handler_${source.datanameUpperCase}(httpd_req_t *req, httpd_err_code_t err) {`);
163
+ if (d.basePath)
164
+ lines.push(` const char* prefix = "${d.basePath}/";`, ` if (strncmp(req->uri, prefix, strlen(prefix)) != 0 && strcmp(req->uri, "${d.basePath}") != 0) {`, ` httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Not found");`, ` return ESP_FAIL;`, ` }`);
165
+ lines.push(` return file_handler_${source.datanameUpperCase}(req);`, `}`);
145
166
  }
146
- {{/case}}
147
- {{#case "compiler"}}
148
- #ifdef {{../definePrefix}}_ENABLE_ETAG
149
- size_t hdr_len = httpd_req_get_hdr_value_len(req, "If-None-Match");
150
- if (hdr_len > 0) {
151
- char* hdr_value = malloc(hdr_len + 1);
152
- if (hdr_value == NULL) { httpd_resp_send_500(req); return ESP_FAIL; }
153
- if (httpd_req_get_hdr_value_str(req, "If-None-Match", hdr_value, hdr_len + 1) == ESP_OK) {
154
- if (strcmp(hdr_value, etag_{{this.dataname}}) == 0) {
155
- free(hdr_value);
156
- httpd_resp_set_status(req, "304 Not Modified");
157
- {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 304);
158
- httpd_resp_send(req, NULL, 0);
159
- return ESP_OK;
160
- }
161
- }
162
- free(hdr_value);
167
+ lines.push(`static inline void ${d.methodName}(httpd_handle_t server) {`);
168
+ for (const source of d.sources) {
169
+ if (source.isDefault)
170
+ lines.push(` httpd_register_uri_handler(server, &route_def_${source.datanameUpperCase});`);
171
+ lines.push(` httpd_register_uri_handler(server, &route_${source.datanameUpperCase});`);
163
172
  }
164
- #endif
165
- {{/case}}
166
- {{/switch}}
167
- httpd_resp_set_type(req, "{{this.mime}}");
168
- {{#switch ../gzip}}
169
- {{#case "always"}}
170
- {{#if this.isGzip}}
171
- httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
172
- {{/if}}
173
- {{/case}}
174
- {{#case "compiler"}}
175
- {{#if this.isGzip}}
176
- #ifdef {{../definePrefix}}_ENABLE_GZIP
177
- httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
178
- #endif
179
- {{/if}}
180
- {{/case}}
181
- {{/switch}}
182
-
183
- {{#switch ../etag}}
184
- {{#case "always"}}
185
- {{#this.cacheTime}}
186
- httpd_resp_set_hdr(req, "Cache-Control", "max-age={{value}}");
187
- {{/this.cacheTime}}
188
- {{^this.cacheTime}}
189
- httpd_resp_set_hdr(req, "Cache-Control", "no-cache");
190
- {{/this.cacheTime}}
191
- httpd_resp_set_hdr(req, "ETag", etag_{{this.dataname}});
192
- {{/case}}
193
- {{#case "compiler"}}
194
- #ifdef {{../definePrefix}}_ENABLE_ETAG
195
- {{#this.cacheTime}}
196
- httpd_resp_set_hdr(req, "Cache-Control", "max-age={{value}}");
197
- {{/this.cacheTime}}
198
- {{^this.cacheTime}}
199
- httpd_resp_set_hdr(req, "Cache-Control", "no-cache");
200
- {{/this.cacheTime}}
201
- httpd_resp_set_hdr(req, "ETag", etag_{{this.dataname}});
202
- #endif
203
- {{/case}}
204
- {{/switch}}
205
-
206
- {{#switch ../gzip}}
207
- {{#case "always"}}
208
- {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 200);
209
- httpd_resp_send(req, (const char *)datagzip_{{this.dataname}}, {{this.lengthGzip}});
210
- {{/case}}
211
- {{#case "never"}}
212
- {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 200);
213
- httpd_resp_send(req, (const char *)data_{{this.dataname}}, {{this.length}});
214
- {{/case}}
215
- {{#case "compiler"}}
216
- {{../definePrefix}}_onFileServed("{{../basePath}}/{{this.filename}}", 200);
217
- #ifdef {{../definePrefix}}_ENABLE_GZIP
218
- httpd_resp_send(req, (const char *)datagzip_{{this.dataname}}, {{this.lengthGzip}});
219
- #else
220
- httpd_resp_send(req, (const char *)data_{{this.dataname}}, {{this.length}});
221
- #endif
222
- {{/case}}
223
- {{/switch}}
224
- return ESP_OK;
225
- }
226
-
227
- {{#if this.isDefault}}
228
- static const httpd_uri_t route_def_{{this.datanameUpperCase}} = {
229
- .uri = "{{#if ../basePath}}{{../basePath}}{{else}}/{{/if}}",
230
- .method = HTTP_GET,
231
- .handler = file_handler_{{this.datanameUpperCase}},
232
- };
233
- {{/if}}
234
-
235
- static const httpd_uri_t route_{{this.datanameUpperCase}} = {
236
- .uri = "{{../basePath}}/{{this.filename}}",
237
- .method = HTTP_GET,
238
- .handler = file_handler_{{this.datanameUpperCase}},
173
+ if (d.spa && d.spaSource)
174
+ lines.push(` httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, spa_handler_${d.spaSource.datanameUpperCase});`);
175
+ lines.push('}');
176
+ return lines.join('\n');
239
177
  };
240
-
241
- {{/each}}
242
-
243
- {{#if spa}}
244
- {{#with spaSource}}
245
- static esp_err_t spa_handler_{{this.datanameUpperCase}}(httpd_req_t *req, httpd_err_code_t err) {
246
- {{#if ../basePath}}
247
- const char* prefix = "{{../basePath}}/";
248
- if (strncmp(req->uri, prefix, strlen(prefix)) != 0 && strcmp(req->uri, "{{../basePath}}") != 0) {
249
- httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Not found");
250
- return ESP_FAIL;
251
- }
252
- {{/if}}
253
- return file_handler_{{this.datanameUpperCase}}(req);
254
- }
255
- {{/with}}
256
- {{/if}}
257
-
258
-
259
- static inline void {{methodName}}(httpd_handle_t server) {
260
- {{#each sources}}
261
- {{#if this.isDefault}}
262
- httpd_register_uri_handler(server, &route_def_{{this.datanameUpperCase}});
263
- {{/if}}
264
- httpd_register_uri_handler(server, &route_{{this.datanameUpperCase}});
265
- {{/each}}
266
- {{#if spa}}
267
- {{#with spaSource}}
268
- httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, spa_handler_{{this.datanameUpperCase}});
269
- {{/with}}
270
- {{/if}}
271
-
272
- }`;
178
+ exports.genEspIdfCpp = genEspIdfCpp;
@@ -0,0 +1,2 @@
1
+ import type { TemplateData } from './cppCode';
2
+ export declare const genPsychicCpp: (d: TemplateData) => string;