protocol_fulltext_demo.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * ws protocol handler plugin for "fulltext demo"
  3. *
  4. * Written in 2010-2019 by Andy Green <[email protected]>
  5. *
  6. * This file is made available under the Creative Commons CC0 1.0
  7. * Universal Public Domain Dedication.
  8. *
  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.
  15. *
  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
  18. * Public Domain.
  19. */
  20. #if !defined (LWS_PLUGIN_STATIC)
  21. #define LWS_DLL
  22. #define LWS_INTERNAL
  23. #include <libwebsockets.h>
  24. #endif
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <fcntl.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #ifdef WIN32
  31. #include <io.h>
  32. #endif
  33. #include <stdio.h>
  34. struct vhd_fts_demo {
  35. const char *indexpath;
  36. };
  37. struct pss_fts_demo {
  38. struct lwsac *result;
  39. struct lws_fts_result_autocomplete *ac;
  40. struct lws_fts_result_filepath *fp;
  41. uint32_t *li;
  42. int done;
  43. uint8_t first:1;
  44. uint8_t ac_done:1;
  45. uint8_t fp_init_done:1;
  46. };
  47. static int
  48. callback_fts(struct lws *wsi, enum lws_callback_reasons reason, void *user,
  49. void *in, size_t len)
  50. {
  51. struct vhd_fts_demo *vhd = (struct vhd_fts_demo *)
  52. lws_protocol_vh_priv_get(lws_get_vhost(wsi),
  53. lws_get_protocol(wsi));
  54. struct pss_fts_demo *pss = (struct pss_fts_demo *)user;
  55. uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start,
  56. *end = &buf[sizeof(buf) - LWS_PRE - 1];
  57. struct lws_fts_search_params params;
  58. const char *ccp = (const char *)in;
  59. struct lws_fts_result *result;
  60. struct lws_fts_file *jtf;
  61. int n;
  62. switch (reason) {
  63. case LWS_CALLBACK_PROTOCOL_INIT:
  64. vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
  65. lws_get_protocol(wsi),sizeof(struct vhd_fts_demo));
  66. if (!vhd)
  67. return 1;
  68. if (lws_pvo_get_str(in, "indexpath",
  69. (const char **)&vhd->indexpath))
  70. return 1;
  71. return 0;
  72. case LWS_CALLBACK_HTTP:
  73. pss->first = 1;
  74. pss->ac_done = 0;
  75. /*
  76. * we have a "subdirectory" selecting the task
  77. *
  78. * /a/ = autocomplete
  79. * /r/ = results
  80. */
  81. if (strncmp(ccp, "/a/", 3) && strncmp(ccp, "/r/", 3))
  82. goto reply_404;
  83. memset(&params, 0, sizeof(params));
  84. params.needle = ccp + 3;
  85. if (*(ccp + 1) == 'a')
  86. params.flags = LWSFTS_F_QUERY_AUTOCOMPLETE;
  87. if (*(ccp + 1) == 'r')
  88. params.flags = LWSFTS_F_QUERY_FILES |
  89. LWSFTS_F_QUERY_FILE_LINES |
  90. LWSFTS_F_QUERY_QUOTE_LINE;
  91. params.max_autocomplete = 10;
  92. params.max_files = 10;
  93. jtf = lws_fts_open(vhd->indexpath);
  94. if (!jtf) {
  95. lwsl_err("unable to open %s\n", vhd->indexpath);
  96. /* we'll inform the client in the JSON */
  97. goto reply_200;
  98. }
  99. result = lws_fts_search(jtf, &params);
  100. lws_fts_close(jtf);
  101. if (result) {
  102. pss->result = params.results_head;
  103. pss->ac = result->autocomplete_head;
  104. pss->fp = result->filepath_head;
  105. }
  106. /* NULL result will be told in the json as "indexed": 0 */
  107. reply_200:
  108. if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
  109. "text/html",
  110. LWS_ILLEGAL_HTTP_CONTENT_LEN, &p, end))
  111. return 1;
  112. if (lws_finalize_write_http_header(wsi, start, &p, end))
  113. return 1;
  114. lws_callback_on_writable(wsi);
  115. return 0;
  116. reply_404:
  117. if (lws_add_http_common_headers(wsi, HTTP_STATUS_NOT_FOUND,
  118. "text/html",
  119. LWS_ILLEGAL_HTTP_CONTENT_LEN, &p, end))
  120. return 1;
  121. if (lws_finalize_write_http_header(wsi, start, &p, end))
  122. return 1;
  123. return lws_http_transaction_completed(wsi);
  124. case LWS_CALLBACK_CLOSED_HTTP:
  125. if (pss && pss->result)
  126. lwsac_free(&pss->result);
  127. break;
  128. case LWS_CALLBACK_HTTP_WRITEABLE:
  129. if (!pss)
  130. break;
  131. n = LWS_WRITE_HTTP;
  132. if (pss->first)
  133. p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
  134. "{\"indexed\": %d, \"ac\": [", !!pss->result);
  135. while (pss->ac && lws_ptr_diff(end, p) > 256) {
  136. p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
  137. "%c{\"ac\": \"%s\",\"matches\": %d,"
  138. "\"agg\": %d, \"elided\": %d}",
  139. pss->first ? ' ' : ',', (char *)(pss->ac + 1),
  140. pss->ac->instances, pss->ac->agg_instances,
  141. pss->ac->elided);
  142. pss->first = 0;
  143. pss->ac = pss->ac->next;
  144. }
  145. if (!pss->ac_done && !pss->ac && pss->fp) {
  146. pss->ac_done = 1;
  147. p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
  148. "], \"fp\": [");
  149. }
  150. while (pss->fp && lws_ptr_diff(end, p) > 256) {
  151. if (!pss->fp_init_done) {
  152. p += lws_snprintf((char *)p,
  153. lws_ptr_diff(end, p),
  154. "%c{\"path\": \"%s\",\"matches\": %d,"
  155. "\"origlines\": %d,"
  156. "\"hits\": [", pss->first ? ' ' : ',',
  157. ((char *)(pss->fp + 1)) +
  158. pss->fp->matches_length,
  159. pss->fp->matches,
  160. pss->fp->lines_in_file);
  161. pss->li = ((uint32_t *)(pss->fp + 1));
  162. pss->done = 0;
  163. pss->fp_init_done = 1;
  164. pss->first = 0;
  165. } else {
  166. while (pss->done < pss->fp->matches &&
  167. lws_ptr_diff(end, p) > 256) {
  168. p += lws_snprintf((char *)p,
  169. lws_ptr_diff(end, p),
  170. "%c\n{\"l\":%d,\"o\":%d,"
  171. "\"s\":\"%s\"}",
  172. !pss->done ? ' ' : ',',
  173. pss->li[0], pss->li[1],
  174. *((const char **)&pss->li[2]));
  175. pss->li += 2 + (sizeof(const char *) /
  176. sizeof(uint32_t));
  177. pss->done++;
  178. }
  179. if (pss->done == pss->fp->matches) {
  180. *p++ = ']';
  181. pss->fp_init_done = 0;
  182. pss->fp = pss->fp->next;
  183. if (!pss->fp)
  184. *p++ = '}';
  185. }
  186. }
  187. }
  188. if (!pss->ac && !pss->fp) {
  189. n = LWS_WRITE_HTTP_FINAL;
  190. p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
  191. "]}");
  192. }
  193. if (lws_write(wsi, (uint8_t *)start,
  194. lws_ptr_diff(p, start), n) !=
  195. lws_ptr_diff(p, start))
  196. return 1;
  197. if (n == LWS_WRITE_HTTP_FINAL) {
  198. if (pss->result)
  199. lwsac_free(&pss->result);
  200. if (lws_http_transaction_completed(wsi))
  201. return -1;
  202. } else
  203. lws_callback_on_writable(wsi);
  204. return 0;
  205. default:
  206. break;
  207. }
  208. return lws_callback_http_dummy(wsi, reason, user, in, len);
  209. }
  210. #define LWS_PLUGIN_PROTOCOL_FULLTEXT_DEMO \
  211. { \
  212. "lws-test-fts", \
  213. callback_fts, \
  214. sizeof(struct pss_fts_demo), \
  215. 0, \
  216. 0, NULL, 0 \
  217. }
  218. #if !defined (LWS_PLUGIN_STATIC)
  219. static const struct lws_protocols protocols[] = {
  220. LWS_PLUGIN_PROTOCOL_FULLTEXT_DEMO
  221. };
  222. LWS_VISIBLE const lws_plugin_protocol_t fulltext_demo = {
  223. .hdr = {
  224. "fulltext demo",
  225. "lws_protocol_plugin",
  226. LWS_PLUGIN_API_MAGIC
  227. },
  228. .protocols = protocols,
  229. .count_protocols = LWS_ARRAY_SIZE(protocols),
  230. .extensions = NULL,
  231. .count_extensions = 0,
  232. };
  233. #endif