DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
webhook.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file webhook.cpp
6 * @brief IFTTT URL / payload builders (pure) + fire over the http_client.
7 */
8
10
11#if DETWS_ENABLE_WEBHOOK
12
14
15#include <stdio.h>
16#include <string.h>
17
18namespace
19{
20bool put(char *out, size_t cap, size_t *pos, const char *s)
21{
22 size_t n = strnlen(s, cap + 1);
23 if (*pos + n >= cap)
24 return false;
25 memcpy(out + *pos, s, n);
26 *pos += n;
27 out[*pos] = '\0';
28 return true;
29}
30
31// Append a JSON string value, escaping '"' and '\'.
32bool put_escaped(char *out, size_t cap, size_t *pos, const char *s)
33{
34 for (; *s; s++)
35 {
36 char c = *s;
37 if (c == '"' || c == '\\')
38 {
39 if (*pos + 2 >= cap)
40 return false;
41 out[(*pos)++] = '\\';
42 out[(*pos)++] = c;
43 }
44 else
45 {
46 if (*pos + 1 >= cap)
47 return false;
48 out[(*pos)++] = c;
49 }
50 out[*pos] = '\0';
51 }
52 return true;
53}
54} // namespace
55
56int detws_ifttt_url(const char *event, const char *key, char *out, size_t cap)
57{
58 if (!out || cap == 0 || !event || !key)
59 {
60 if (out && cap)
61 out[0] = '\0';
62 return 0;
63 }
64 int w = snprintf(out, cap, "https://maker.ifttt.com/trigger/%s/with/key/%s", event, key);
65 if (w < 0 || (size_t)w >= cap)
66 {
67 out[0] = '\0';
68 return 0;
69 }
70 return w;
71}
72
73int detws_ifttt_payload(const char *v1, const char *v2, const char *v3, char *out, size_t cap)
74{
75 if (!out || cap == 0)
76 return 0;
77 out[0] = '\0';
78 size_t pos = 0;
79 bool ok = put(out, cap, &pos, "{");
80 const char *names[3] = {"value1", "value2", "value3"};
81 const char *vals[3] = {v1, v2, v3};
82 bool first = true;
83 for (int i = 0; i < 3 && ok; i++)
84 {
85 if (!vals[i])
86 continue;
87 if (!first)
88 ok = ok && put(out, cap, &pos, ",");
89 first = false;
90 ok = ok && put(out, cap, &pos, "\"");
91 ok = ok && put(out, cap, &pos, names[i]);
92 ok = ok && put(out, cap, &pos, "\":\"");
93 ok = ok && put_escaped(out, cap, &pos, vals[i]);
94 ok = ok && put(out, cap, &pos, "\"");
95 }
96 ok = ok && put(out, cap, &pos, "}");
97 if (!ok)
98 {
99 out[0] = '\0';
100 return 0;
101 }
102 return (int)pos;
103}
104
105#if DETWS_ENABLE_HTTP_CLIENT
106
108
109int detws_webhook_post(const char *url, const char *json)
110{
111 if (!url || !json)
112 return (int)HttpClientError::HTTP_CLIENT_ERR_URL;
113 HttpClientResult r;
114 return http_post(url, DET_MIME_JSON, (const uint8_t *)json, strnlen(json, DETWS_HTTP_CLIENT_BUF_SIZE), &r);
115}
116
117#else // http_client not enabled in this build
118
119int detws_webhook_post(const char *, const char *)
120{
121 return -1;
122}
123
124#endif // DETWS_ENABLE_HTTP_CLIENT
125
126int detws_ifttt_trigger(const char *event, const char *key, const char *v1, const char *v2, const char *v3)
127{
128 char url[160];
129 char body[256];
130 if (detws_ifttt_url(event, key, url, sizeof(url)) == 0)
131 return -1;
132 if (detws_ifttt_payload(v1, v2, v3, body, sizeof(body)) == 0)
133 return -1;
134 return detws_webhook_post(url, body);
135}
136
137#endif // DETWS_ENABLE_WEBHOOK
#define DETWS_HTTP_CLIENT_BUF_SIZE
Receive buffer (and max response size) for the outbound HTTP client, bytes.
Zero-heap outbound HTTP(S) client over raw lwIP (DETWS_ENABLE_HTTP_CLIENT).
Shared HTTP Content-Type ("MIME") string constants (one source of truth).
Outbound webhooks / IFTTT (DETWS_ENABLE_WEBHOOK).