• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "jbr.h"
2 #include "ejdb2cfg.h"
3 
4 #include <iowow/iwpool.h>
5 #include <iowow/iwconv.h>
6 #include <iwnet/iwn_utils.h>
7 
8 #include <stdio.h>
9 #include <errno.h>
10 #include <ctype.h>
11 #include <unistd.h>
12 #include <getopt.h>
13 #include <signal.h>
14 
15 struct env {
16   const char *program;
17   EJDB      db;
18   EJDB_OPTS opts;
19   IWPOOL   *pool;
20 } env;
21 
_usage(const char * err)22 static int _usage(const char *err) {
23   if (err) {
24     fprintf(stderr, "\n%s\n", err);
25   }
26   fprintf(stderr, "\n\tEJDB " EJDB2_VERSION " HTTP REST/Websocket server. http://ejdb.org\n");
27   fprintf(stderr, "\nUsage:\n\n\t %s [options]\n\n", env.program);
28   fprintf(stderr, "\t-v, --version\t\tPrint program version.\n");
29   fprintf(stderr, "\t-f, --file=<>\t\tDatabase file path. Default: ejdb2.db\n");
30   fprintf(stderr, "\t-p, --port=NUM\t\tHTTP server port numer. Default: 9191\n");
31   fprintf(stderr, "\t-l, --listen=<>\t\tNetwork address server will listen. Default: localhost\n");
32   fprintf(stderr, "\t-k, --key=<>\t\tPEM private key file for TLS 1.2 HTTP server.\n");
33   fprintf(stderr, "\t-c, --certs=<>\t\tPEM certificates file for TLS 1.2 HTTP server.\n");
34   fprintf(stderr, "\t-a, --access=TOKEN|@FILE\t\tAccess token to match 'X-Access-Token' HTTP header value.\n");
35   fprintf(stderr, "\t-r, --access-read\t\tAllows unrestricted read-only data access.\n");
36   fprintf(stderr, "\t-C, --cors\t\tEnable COSR response headers for HTTP server\n");
37   fprintf(stderr, "\t-t, --trunc\t\tCleanup/reset database file on open.\n");
38   fprintf(stderr, "\t-w, --wal\t\tuse the write ahead log (WAL). Used to provide data durability.\n");
39   fprintf(stderr, "\nAdvanced options:\n");
40   fprintf(stderr,
41           "\t-S, --sbz=NUM\t\tMax sorting buffer size. If exceeded, an overflow temp file for data will be created."
42           "Default: 16777216, min: 1048576\n");
43   fprintf(stderr, "\t-D, --dsz=NUM\t\tInitial size of buffer to process/store document on queries."
44           " Preferable average size of document. Default: 65536, min: 16384\n");
45   fprintf(stderr, "\t-T, --trylock Exit with error if database is locked by another process."
46           " If not set, current process will wait for lock release.");
47   fprintf(stderr, "\n\n");
48   return 1;
49 }
50 
_on_signal(int signo)51 static void _on_signal(int signo) {
52   if (env.db) {
53     jbr_shutdown_request(env.db);
54   }
55 }
56 
_version(void)57 static void _version(void) {
58   fprintf(stdout, EJDB2_VERSION);
59 }
60 
main(int argc,char * argv[])61 int main(int argc, char *argv[]) {
62   signal(SIGPIPE, SIG_IGN);
63   signal(SIGHUP, SIG_IGN);
64   signal(SIGALRM, SIG_IGN);
65   signal(SIGUSR1, SIG_IGN);
66   signal(SIGUSR2, SIG_IGN);
67   if (signal(SIGTERM, _on_signal) == SIG_ERR) {
68     return EXIT_FAILURE;
69   }
70   if (signal(SIGINT, _on_signal) == SIG_ERR) {
71     return EXIT_FAILURE;
72   }
73 
74   IWPOOL *pool;
75   int ec = 0, ch;
76 
77   env.program = argc ? argv[0] : "";
78   env.opts.http.enabled = true;
79   env.opts.http.blocking = true;
80   env.opts.no_wal = true;
81 
82   iwrc rc = ejdb_init();
83   if (rc) {
84     iwlog_ecode_error3(rc);
85     return EXIT_FAILURE;
86   }
87 
88   RCA(pool = env.pool = iwpool_create_empty(), finish);
89 
90   static const struct option long_options[] = {
91     { "help",        0, 0, 'h' },
92     { "version",     0, 0, 'v' },
93     { "file",        1, 0, 'f' },
94     { "port",        1, 0, 'p' },
95     { "bind",        1, 0, 'b' }, // for backward compatibility
96     { "listen",      1, 0, 'l' },
97     { "key",         1, 0, 'k' },
98     { "certs",       1, 0, 'c' },
99     { "access",      1, 0, 'a' },
100     { "access-read", 0, 0, 'r' },
101     { "cors",        0, 0, 'C' },
102     { "trunc",       0, 0, 't' },
103     { "wal",         0, 0, 'w' },
104     { "sbz",         1, 0, 'S' },
105     { "dsz",         1, 0, 'D' },
106     { "trylock",     0, 0, 'T' }
107   };
108 
109   while ((ch = getopt_long(argc, argv, "f:p:b:l:k:c:a:S:D:rCtwThv", long_options, 0)) != -1) {
110     switch (ch) {
111       case 'h':
112         ec = _usage(0);
113         goto finish;
114       case 'v':
115         _version();
116         goto finish;
117       case 'f':
118         env.opts.kv.path = iwpool_strdup2(pool, optarg);
119         break;
120       case 'p':
121         env.opts.http.port = iwatoi(optarg);
122         break;
123       case 'b':
124       case 'l':
125         env.opts.http.bind = iwpool_strdup2(pool, optarg);
126         break;
127       case 'k':
128         env.opts.http.ssl_private_key = iwpool_strdup2(pool, optarg);
129         break;
130       case 'c':
131         env.opts.http.ssl_certs = iwpool_strdup2(pool, optarg);
132         break;
133       case 'a':
134         env.opts.http.access_token = iwpool_strdup2(pool, optarg);
135         env.opts.http.access_token_len = env.opts.http.access_token ? strlen(env.opts.http.access_token) : 0;
136         break;
137       case 'C':
138         env.opts.http.cors = true;
139         break;
140       case 't':
141         env.opts.kv.oflags |= IWKV_TRUNC;
142         break;
143       case 'w':
144         env.opts.no_wal = false;
145         break;
146       case 'S':
147         env.opts.sort_buffer_sz = iwatoi(optarg);
148         break;
149       case 'D':
150         env.opts.document_buffer_sz = iwatoi(optarg);
151         break;
152       case 'T':
153         env.opts.kv.file_lock_fail_fast = true;
154         break;
155       case 'r':
156         env.opts.http.read_anon = true;
157         break;
158       default:
159         ec = _usage(0);
160         goto finish;
161     }
162   }
163 
164   if (!env.opts.kv.path) {
165     env.opts.kv.path = "ejdb2.db";
166   }
167   if (env.opts.http.port < 1) {
168     env.opts.http.port = 9191;
169   }
170   if (env.opts.sort_buffer_sz < 1) {
171     env.opts.sort_buffer_sz = 16777216;
172   } else if (env.opts.sort_buffer_sz < 1048576) {
173     env.opts.sort_buffer_sz = 1048576;
174   }
175   if (env.opts.document_buffer_sz < 1) {
176     env.opts.document_buffer_sz = 65536;
177   } else if (env.opts.document_buffer_sz < 16384) {
178     env.opts.document_buffer_sz = 16384;
179   }
180 
181   RCC(rc, finish, ejdb_open(&env.opts, &env.db));
182   RCC(rc, finish, ejdb_close(&env.db));
183 
184 finish:
185   if (rc) {
186     iwlog_ecode_error3(rc);
187   }
188   iwpool_destroy(env.pool);
189   fflush(0);
190   return rc == 0 ? ec : 1;
191 }
192