Added subject facet browsing, beginning of relevance ranking
[pazpar2-moved-to-github.git] / http_command.c
1 /*
2  * $Id: http_command.c,v 1.2 2006-11-24 20:29:07 quinn Exp $
3  */
4
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <sys/uio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <strings.h>
11 #include <ctype.h>
12 #include <sys/time.h>
13
14 #include <yaz/yaz-util.h>
15
16 #include "command.h"
17 #include "util.h"
18 #include "eventl.h"
19 #include "pazpar2.h"
20 #include "http.h"
21 #include "http_command.h"
22
23 struct http_session {
24     struct session *psession;
25     int session_id;
26     int timestamp;
27     struct http_session *next;
28 };
29
30 static struct http_session *session_list = 0;
31
32 struct http_session *http_session_create()
33 {
34     struct http_session *r = xmalloc(sizeof(*r));
35     r->psession = new_session();
36     r->session_id = 0;
37     r->timestamp = 0;
38     r->next = session_list;
39     session_list = r;
40     return r;
41 }
42
43 void http_session_destroy(struct http_session *s)
44 {
45     struct http_session **p;
46
47     for (p = &session_list; *p; p = &(*p)->next)
48         if (*p == s)
49         {
50             *p = (*p)->next;
51             break;
52         }
53     session_destroy(s->psession);
54     xfree(s);
55 }
56
57 static void error(struct http_response *rs, char *code, char *msg, char *txt)
58 {
59     struct http_channel *c = rs->channel;
60     char tmp[1024];
61
62     if (!txt)
63         txt = msg;
64     rs->msg = nmem_strdup(c->nmem, msg);
65     strcpy(rs->code, code);
66     sprintf(tmp, "<error code=\"general\">%s</error>", txt);
67     rs->payload = nmem_strdup(c->nmem, tmp);
68 }
69
70 int  make_sessionid()
71 {
72     struct timeval t;
73     int res;
74     static int seq = 0;
75
76     seq++;
77     if (gettimeofday(&t, 0) < 0)
78         abort();
79     res = t.tv_sec;
80     res = (res << 8) | (seq & 0xff);
81     return res;
82 }
83
84 static struct http_session *locate_session(struct http_request *rq, struct http_response *rs)
85 {
86     struct http_session *p;
87     char *session = http_argbyname(rq, "session");
88     int id;
89
90     if (!session)
91     {
92         error(rs, "417", "Must supply session", 0);
93         return 0;
94     }
95     id = atoi(session);
96     for (p = session_list; p; p = p->next)
97         if (id == p->session_id)
98             return p;
99     error(rs, "417", "Session does not exist, or it has expired", 0);
100     return 0;
101 }
102
103
104 static void cmd_init(struct http_request *rq, struct http_response *rs)
105 {
106     int sesid;
107     char buf[1024];
108     struct http_session *s = http_session_create();
109
110     // FIXME create a pazpar2 session
111     yaz_log(YLOG_DEBUG, "HTTP Session init");
112     sesid = make_sessionid();
113     s->session_id = sesid;
114     sprintf(buf, "<init><status>OK</status><session>%d</session></init>", sesid);
115     rs->payload = nmem_strdup(rq->channel->nmem, buf);
116 }
117
118 static void cmd_termlist(struct http_request *rq, struct http_response *rs)
119 {
120     struct http_session *s = locate_session(rq, rs);
121     struct http_channel *c = rq->channel;
122     struct termlist_score **p;
123     int len;
124     int i;
125
126     if (!s)
127         return;
128     wrbuf_rewind(c->wrbuf);
129
130     wrbuf_puts(c->wrbuf, "<termlist>");
131     p = termlist(s->psession, &len);
132     if (p)
133         for (i = 0; i < len; i++)
134         {
135             wrbuf_puts(c->wrbuf, "\n<term>");
136             wrbuf_printf(c->wrbuf, "<name>%s</name>", p[i]->term);
137             wrbuf_printf(c->wrbuf, "<frequency>%d</frequency>", p[i]->frequency);
138             wrbuf_puts(c->wrbuf, "</term>");
139         }
140     wrbuf_puts(c->wrbuf, "</termlist>");
141     rs->payload = nmem_strdup(rq->channel->nmem, wrbuf_buf(c->wrbuf));
142 }
143
144
145 static void cmd_bytarget(struct http_request *rq, struct http_response *rs)
146 {
147     struct http_session *s = locate_session(rq, rs);
148     struct http_channel *c = rq->channel;
149     struct hitsbytarget *ht;
150     int count, i;
151
152     if (!s)
153         return;
154     if (!(ht = hitsbytarget(s->psession, &count)))
155     {
156         error(rs, "500", "Failed to retrieve hitcounts", 0);
157         return;
158     }
159     wrbuf_rewind(c->wrbuf);
160     wrbuf_puts(c->wrbuf, "<bytarget><status>OK</status>");
161
162     for (i = 0; i < count; i++)
163     {
164         wrbuf_puts(c->wrbuf, "\n<target>");
165         wrbuf_printf(c->wrbuf, "<id>%s</id>\n", ht[i].id);
166         wrbuf_printf(c->wrbuf, "<hits>%d</hits>\n", ht[i].hits);
167         wrbuf_printf(c->wrbuf, "<diagnostic>%d</diagnostic>\n", ht[i].diagnostic);
168         wrbuf_printf(c->wrbuf, "<records>%d</records>\n", ht[i].records);
169         wrbuf_printf(c->wrbuf, "<state>%s</state>\n", ht[i].state);
170         wrbuf_puts(c->wrbuf, "</target>");
171     }
172
173     wrbuf_puts(c->wrbuf, "</bytarget>");
174     rs->payload = nmem_strdup(c->nmem, wrbuf_buf(c->wrbuf));
175 }
176
177 static void cmd_show(struct http_request *rq, struct http_response *rs)
178 {
179     struct http_session *s = locate_session(rq, rs);
180     struct http_channel *c = rq->channel;
181     struct record **rl;
182     char *start = http_argbyname(rq, "start");
183     char *num = http_argbyname(rq, "num");
184     int startn = 0;
185     int numn = 20;
186     int i;
187
188     if (!s)
189         return;
190
191     if (start)
192         startn = atoi(start);
193     if (num)
194         numn = atoi(num);
195
196     rl = show(s->psession, startn, &numn);
197
198     wrbuf_rewind(c->wrbuf);
199     wrbuf_puts(c->wrbuf, "<show>\n<status>OK</status>\n");
200
201     for (i = 0; i < numn; i++)
202     {
203         int ccount;
204         struct record *p;
205
206         wrbuf_puts(c->wrbuf, "<hit>\n");
207         wrbuf_printf(c->wrbuf, "<merge_key>%s</merge_key>\n", rl[i]->merge_key);
208         for (ccount = 1, p = rl[i]->next_cluster; p;  p = p->next_cluster, ccount++)
209             ;
210         if (ccount > 1)
211             wrbuf_printf(c->wrbuf, "<count>%d</count>\n", ccount);
212         wrbuf_puts(c->wrbuf, "</hit>\n");
213     }
214
215     wrbuf_puts(c->wrbuf, "</show>\n");
216     rs->payload = nmem_strdup(c->nmem, wrbuf_buf(c->wrbuf));
217 }
218
219 static void cmd_search(struct http_request *rq, struct http_response *rs)
220 {
221     struct http_session *s = locate_session(rq, rs);
222     char *query = http_argbyname(rq, "query");
223
224     if (!s)
225         return;
226     if (!query)
227     {
228         error(rs, "417", "Must supply query", 0);
229         return;
230     }
231     search(s->psession, query);
232     rs->payload = "<search><status>OK</status></search>";
233 }
234
235
236 static void cmd_stat(struct http_request *rq, struct http_response *rs)
237 {
238 }
239
240 static void cmd_load(struct http_request *rq, struct http_response *rs)
241 {
242     struct http_session *s = locate_session(rq, rs);
243     char *fn = http_argbyname(rq, "name");
244
245     if (!s)
246         return;
247     if (!fn)
248     {
249         error(rs, "417", "Must suppply name", 0);
250         return;
251     }
252     if (load_targets(s->psession, fn) < 0)
253         error(rs, "417", "Failed to find targets", "Possibly wrong filename");
254     else
255         rs->payload = "<load><status>OK</status></load>";
256 }
257
258 struct {
259     char *name;
260     void (*fun)(struct http_request *rq, struct http_response *rs);
261 } commands[] = {
262     { "init", cmd_init },
263     { "stat", cmd_stat },
264     { "load", cmd_load },
265     { "bytarget", cmd_bytarget },
266     { "show", cmd_show },
267     { "search", cmd_search },
268     { "termlist", cmd_termlist },
269     {0,0}
270 };
271
272 struct http_response *http_command(struct http_request *rq)
273 {
274     char *command = http_argbyname(rq, "command");
275     struct http_channel *c = rq->channel;
276     struct http_response *rs = http_create_response(c);
277     int i;
278
279     if (!command)
280     {
281         error(rs, "417", "Must supply command", 0);
282         return rs;
283     }
284     for (i = 0; commands[i].name; i++)
285         if (!strcmp(commands[i].name, command))
286         {
287             (*commands[i].fun)(rq, rs);
288             break;
289         }
290     if (!commands[i].name)
291         error(rs, "417", "Unknown command", 0);
292
293     return rs;
294 }
295
296 /*
297  * Local variables:
298  * c-basic-offset: 4
299  * indent-tabs-mode: nil
300  * End:
301  * vim: shiftwidth=4 tabstop=8 expandtab
302  */