2 * ws protocol handler plugin for "fulltext demo"
4 * Written in 2010-2019 by Andy Green <andy@warmcat.com>
6 * This file is made available under the Creative Commons CC0 1.0
7 * Universal Public Domain Dedication.
9 * The person who associated a work with this deed has dedicated
10 * the work to the public domain by waiving all of his or her rights
11 * to the work worldwide under copyright law, including all related
12 * and neighboring rights, to the extent allowed by law. You can copy,
13 * modify, distribute and perform the work, even for commercial purposes,
14 * all without asking permission.
16 * These test plugins are intended to be adapted for use in your code, which
17 * may be proprietary. So unlike the library itself, they are licensed
21 #if !defined (LWS_PLUGIN_STATIC)
24 #include <libwebsockets.h>
30 #include <sys/types.h>
38 const char *indexpath;
43 struct lws_fts_result_autocomplete *ac;
44 struct lws_fts_result_filepath *fp;
52 uint8_t fp_init_done:1;
56 callback_fts(struct lws *wsi, enum lws_callback_reasons reason, void *user,
59 struct vhd_fts_demo *vhd = (struct vhd_fts_demo *)
60 lws_protocol_vh_priv_get(lws_get_vhost(wsi),
61 lws_get_protocol(wsi));
62 struct pss_fts_demo *pss = (struct pss_fts_demo *)user;
63 uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start,
64 *end = &buf[sizeof(buf) - LWS_PRE - 1];
65 struct lws_fts_search_params params;
66 const char *ccp = (const char *)in;
67 struct lws_fts_result *result;
68 struct lws_fts_file *jtf;
73 case LWS_CALLBACK_PROTOCOL_INIT:
74 vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
75 lws_get_protocol(wsi),sizeof(struct vhd_fts_demo));
78 if (lws_pvo_get_str(in, "indexpath",
79 (const char **)&vhd->indexpath))
84 case LWS_CALLBACK_HTTP:
90 * we have a "subdirectory" selecting the task
96 if (strncmp(ccp, "/a/", 3) && strncmp(ccp, "/r/", 3))
99 memset(¶ms, 0, sizeof(params));
101 params.needle = ccp + 3;
102 if (*(ccp + 1) == 'a')
103 params.flags = LWSFTS_F_QUERY_AUTOCOMPLETE;
104 if (*(ccp + 1) == 'r')
105 params.flags = LWSFTS_F_QUERY_FILES |
106 LWSFTS_F_QUERY_FILE_LINES |
107 LWSFTS_F_QUERY_QUOTE_LINE;
108 params.max_autocomplete = 10;
109 params.max_files = 10;
111 jtf = lws_fts_open(vhd->indexpath);
113 lwsl_err("unable to open %s\n", vhd->indexpath);
114 /* we'll inform the client in the JSON */
118 result = lws_fts_search(jtf, ¶ms);
121 pss->result = params.results_head;
122 pss->ac = result->autocomplete_head;
123 pss->fp = result->filepath_head;
125 /* NULL result will be told in the json as "indexed": 0 */
128 if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
130 LWS_ILLEGAL_HTTP_CONTENT_LEN, &p, end))
133 if (lws_finalize_write_http_header(wsi, start, &p, end))
136 lws_callback_on_writable(wsi);
140 if (lws_add_http_common_headers(wsi, HTTP_STATUS_NOT_FOUND,
142 LWS_ILLEGAL_HTTP_CONTENT_LEN, &p, end))
145 if (lws_finalize_write_http_header(wsi, start, &p, end))
147 return lws_http_transaction_completed(wsi);
149 case LWS_CALLBACK_CLOSED_HTTP:
150 if (pss && pss->result)
151 lwsac_free(&pss->result);
154 case LWS_CALLBACK_HTTP_WRITEABLE:
161 p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
162 "{\"indexed\": %d, \"ac\": [", !!pss->result);
164 while (pss->ac && lws_ptr_diff(end, p) > 256) {
165 p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
166 "%c{\"ac\": \"%s\",\"matches\": %d,"
167 "\"agg\": %d, \"elided\": %d}",
168 pss->first ? ' ' : ',', (char *)(pss->ac + 1),
169 pss->ac->instances, pss->ac->agg_instances,
173 pss->ac = pss->ac->next;
176 if (!pss->ac_done && !pss->ac && pss->fp) {
179 p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
183 while (pss->fp && lws_ptr_diff(end, p) > 256) {
184 if (!pss->fp_init_done) {
185 p += lws_snprintf((char *)p,
186 lws_ptr_diff(end, p),
187 "%c{\"path\": \"%s\",\"matches\": %d,"
189 "\"hits\": [", pss->first ? ' ' : ',',
190 ((char *)(pss->fp + 1)) +
191 pss->fp->matches_length,
193 pss->fp->lines_in_file);
195 pss->li = ((uint32_t *)(pss->fp + 1));
197 pss->fp_init_done = 1;
200 while (pss->done < pss->fp->matches &&
201 lws_ptr_diff(end, p) > 256) {
203 p += lws_snprintf((char *)p,
204 lws_ptr_diff(end, p),
205 "%c\n{\"l\":%d,\"o\":%d,"
207 !pss->done ? ' ' : ',',
208 pss->li[0], pss->li[1],
209 *((const char **)&pss->li[2]));
210 pss->li += 2 + (sizeof(const char *) /
215 if (pss->done == pss->fp->matches) {
217 pss->fp_init_done = 0;
218 pss->fp = pss->fp->next;
225 if (!pss->ac && !pss->fp) {
226 n = LWS_WRITE_HTTP_FINAL;
227 p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
231 if (lws_write(wsi, (uint8_t *)start,
232 lws_ptr_diff(p, start), n) !=
233 lws_ptr_diff(p, start))
236 if (n == LWS_WRITE_HTTP_FINAL) {
238 lwsac_free(&pss->result);
239 if (lws_http_transaction_completed(wsi))
242 lws_callback_on_writable(wsi);
250 return lws_callback_http_dummy(wsi, reason, user, in, len);
254 #define LWS_PLUGIN_PROTOCOL_FULLTEXT_DEMO \
258 sizeof(struct pss_fts_demo), \
263 #if !defined (LWS_PLUGIN_STATIC)
265 static const struct lws_protocols protocols[] = {
266 LWS_PLUGIN_PROTOCOL_FULLTEXT_DEMO
269 LWS_EXTERN LWS_VISIBLE int
270 init_protocol_fulltext_demo(struct lws_context *context,
271 struct lws_plugin_capability *c)
273 if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
274 lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
279 c->protocols = protocols;
280 c->count_protocols = LWS_ARRAY_SIZE(protocols);
281 c->extensions = NULL;
282 c->count_extensions = 0;
287 LWS_EXTERN LWS_VISIBLE int
288 destroy_protocol_fulltext_demo(struct lws_context *context)