~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/json_server/json_server.cc

  • Committer: Mark Atwood
  • Date: 2011-05-12 22:20:08 UTC
  • mfrom: (2283.4.17 json-interface)
  • Revision ID: me@mark.atwood.name-20110512222008-7facdn0qu7lsbm0g
mergeĀ lp:~stewart/drizzle/json-interface

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2011 Stewart Smith
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 */
 
20
 
 
21
 
 
22
#include <config.h>
 
23
#include <drizzled/module/module.h>
 
24
#include <drizzled/module/context.h>
 
25
#include <drizzled/plugin/plugin.h>
 
26
#include <drizzled/plugin.h>
 
27
#include <drizzled/sys_var.h>
 
28
#include <drizzled/gettext.h>
 
29
#include <drizzled/error.h>
 
30
#include <drizzled/query_id.h>
 
31
#include <drizzled/session.h>
 
32
#include <drizzled/internal/my_sys.h>
 
33
#include <drizzled/internal/m_string.h>
 
34
#include <algorithm>
 
35
#include <iostream>
 
36
#include <boost/program_options.hpp>
 
37
#include <drizzled/module/option_map.h>
 
38
#include <drizzled/constrained_value.h>
 
39
#include <evhttp.h>
 
40
#include <event.h>
 
41
#include <pthread.h>
 
42
#include <drizzled/execute.h>
 
43
#include <drizzled/sql/result_set.h>
 
44
 
 
45
#include <drizzled/plugin/listen.h>
 
46
#include <drizzled/plugin/client.h>
 
47
#include <drizzled/catalog/local.h>
 
48
 
 
49
#include <drizzled/version.h>
 
50
#include <plugin/json_server/json/json.h>
 
51
 
 
52
namespace po= boost::program_options;
 
53
using namespace drizzled;
 
54
using namespace std;
 
55
 
 
56
namespace drizzle_plugin
 
57
{
 
58
namespace json_server
 
59
{
 
60
 
 
61
static port_constraint port;
 
62
struct event_base *base= NULL;
 
63
struct evhttp *httpd;
 
64
 
 
65
static in_port_t getPort(void)
 
66
{
 
67
  return port.get();
 
68
}
 
69
 
 
70
extern "C" void process_request(struct evhttp_request *req, void* );
 
71
extern "C" void process_root_request(struct evhttp_request *req, void* );
 
72
extern "C" void process_api01_version_req(struct evhttp_request *req, void* );
 
73
extern "C" void process_api01_sql_req(struct evhttp_request *req, void* );
 
74
 
 
75
extern "C" void process_request(struct evhttp_request *req, void* )
 
76
{
 
77
  struct evbuffer *buf = evbuffer_new();
 
78
  if (buf == NULL) return;
 
79
  evbuffer_add_printf(buf, "Requested: %s\n", evhttp_request_uri(req));
 
80
  evhttp_send_reply(req, HTTP_OK, "OK", buf);
 
81
}
 
82
 
 
83
extern "C" void process_root_request(struct evhttp_request *req, void* )
 
84
{
 
85
  struct evbuffer *buf = evbuffer_new();
 
86
  if (buf == NULL) return;
 
87
 
 
88
  std::string output;
 
89
 
 
90
  output.append("<html><head><title>JSON DATABASE interface demo</title></head>"
 
91
                "<body>"
 
92
                "<script lang=\"javascript\">"
 
93
                "function to_table(obj) {"
 
94
                " var str = '<table>';"
 
95
                "for (var r=0; r< obj.length; r++) {"
 
96
                " str+='<tr>';"
 
97
                "  for (var c=0; c < obj[r].length; c++) {"
 
98
                "    str+= '<td>' + obj[r][c] + '</td>';"
 
99
                "  }"
 
100
                " str+='</tr>';"
 
101
                "}"
 
102
                "str+='</table>';"
 
103
                "return str;"
 
104
                "}"
 
105
                "function run_query()\n"
 
106
                "{"
 
107
                "var url = document.getElementById(\"baseurl\").innerHTML;\n"
 
108
                "var query= document.getElementById(\"query\").value;\n"
 
109
                "var xmlHttp = new XMLHttpRequest();\n"
 
110
                "xmlHttp.onreadystatechange = function () {\n"
 
111
                "if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {\n"
 
112
                "var info = eval ( \"(\" + xmlHttp.responseText + \")\" );\n"
 
113
                "document.getElementById( \"resultset\").innerHTML= to_table(info.result_set);\n"
 
114
                "}\n"
 
115
                "};\n"
 
116
                "xmlHttp.open(\"POST\", url + \"/0.1/sql\", true);"
 
117
                "xmlHttp.send(query);"
 
118
                "}"
 
119
                "\n\n"
 
120
                "function update_version()\n"
 
121
                "{drizzle_version(document.getElementById(\"baseurl\").innerHTML);}\n\n"
 
122
                "function drizzle_version($url)"
 
123
                "{"
 
124
                "var xmlHttp = new XMLHttpRequest();\n"
 
125
                "xmlHttp.onreadystatechange = function () {\n"
 
126
                "if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {\n"
 
127
                "var info = eval ( \"(\" + xmlHttp.responseText + \")\" );\n"
 
128
                "document.getElementById( \"drizzleversion\").innerHTML= info.version;\n"
 
129
                "}\n"
 
130
                "};\n"
 
131
                "xmlHttp.open(\"GET\", $url + \"/0.1/version\", true);"
 
132
                "xmlHttp.send(null);"
 
133
                "}"
 
134
                "</script>"
 
135
                "<p>Drizzle Server at: <a id=\"baseurl\">http://localhost:8765</a></p>"
 
136
                "<p>Drizzle server version: <a id=\"drizzleversion\"></a></p>"
 
137
                "<p><textarea rows=\"3\" cols=\"40\" id=\"query\">"
 
138
                "SELECT * from DATA_DICTIONARY.GLOBAL_STATUS;"
 
139
                "</textarea>"
 
140
                "<button type=\"button\" onclick=\"run_query();\">Execute Query</button>"
 
141
                "<div id=\"resultset\"/>"
 
142
                "<script lang=\"javascript\">update_version(); run_query();</script>"
 
143
                "</body></html>");
 
144
 
 
145
  evbuffer_add(buf, output.c_str(), output.length());
 
146
  evhttp_send_reply(req, HTTP_OK, "OK", buf);
 
147
}
 
148
 
 
149
extern "C" void process_api01_version_req(struct evhttp_request *req, void* )
 
150
{
 
151
  struct evbuffer *buf = evbuffer_new();
 
152
  if (buf == NULL) return;
 
153
 
 
154
  Json::Value root;
 
155
  root["version"]= ::drizzled::version();
 
156
 
 
157
  Json::StyledWriter writer;
 
158
  std::string output= writer.write(root);
 
159
 
 
160
  evbuffer_add(buf, output.c_str(), output.length());
 
161
  evhttp_send_reply(req, HTTP_OK, "OK", buf);
 
162
}
 
163
 
 
164
extern "C" void process_api01_sql_req(struct evhttp_request *req, void* )
 
165
{
 
166
  struct evbuffer *buf = evbuffer_new();
 
167
  if (buf == NULL) return;
 
168
 
 
169
  std::string input;
 
170
  char buffer[1024];
 
171
  int l=0;
 
172
  do {
 
173
    l= evbuffer_remove(req->input_buffer, buffer, 1024);
 
174
    input.append(buffer, l);
 
175
  }while(l);
 
176
 
 
177
  drizzled::Session::shared_ptr _session= drizzled::Session::make_shared(drizzled::plugin::Listen::getNullClient(),
 
178
                                           drizzled::catalog::local());
 
179
  drizzled::identifier::user::mptr user_id= identifier::User::make_shared();
 
180
  user_id->setUser("");
 
181
  _session->setUser(user_id);
 
182
  _session->set_db("test");
 
183
 
 
184
  drizzled::Execute execute(*(_session.get()), true);
 
185
 
 
186
  drizzled::sql::ResultSet result_set(1);
 
187
 
 
188
  /* Execute wraps the SQL to run within a transaction */
 
189
  execute.run(input, result_set);
 
190
  drizzled::sql::Exception exception= result_set.getException();
 
191
 
 
192
  drizzled::error_t err= exception.getErrorCode();
 
193
 
 
194
  Json::Value root;
 
195
  root["sqlstate"]= exception.getSQLState();
 
196
 
 
197
  if ((err != drizzled::EE_OK) && (err != drizzled::ER_EMPTY_QUERY))
 
198
  {
 
199
    root["error_message"]= exception.getErrorMessage();
 
200
    root["error_code"]= exception.getErrorCode();
 
201
  }
 
202
 
 
203
  while (result_set.next())
 
204
  {
 
205
    Json::Value json_row;
 
206
    for (size_t x= 0; x < result_set.getMetaData().getColumnCount(); x++)
 
207
    {
 
208
      if (not result_set.isNull(x))
 
209
      {
 
210
        json_row[x]= result_set.getString(x);
 
211
      }
 
212
    }
 
213
    root["result_set"].append(json_row);
 
214
  }
 
215
 
 
216
  root["query"]= input;
 
217
 
 
218
  Json::StyledWriter writer;
 
219
  std::string output= writer.write(root);
 
220
 
 
221
  evbuffer_add(buf, output.c_str(), output.length());
 
222
  evhttp_send_reply(req, HTTP_OK, "OK", buf);
 
223
}
 
224
 
 
225
extern "C" void *libevent_thread(void*);
 
226
 
 
227
extern "C" void *libevent_thread(void*)
 
228
{
 
229
  internal::my_thread_init();
 
230
 
 
231
  event_base_dispatch(base);
 
232
  evhttp_free(httpd);
 
233
  return NULL;
 
234
}
 
235
 
 
236
static int json_server_init(drizzled::module::Context &context)
 
237
{
 
238
  context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
 
239
 
 
240
  base= event_init();
 
241
  httpd= evhttp_new(base);
 
242
  if (httpd == NULL)
 
243
    return -1;
 
244
 
 
245
  int r= evhttp_bind_socket(httpd, "0.0.0.0", getPort());
 
246
 
 
247
  if (r != 0)
 
248
    return -2;
 
249
 
 
250
  evhttp_set_cb(httpd, "/", process_root_request, NULL);
 
251
  evhttp_set_cb(httpd, "/0.1/version", process_api01_version_req, NULL);
 
252
  evhttp_set_cb(httpd, "/0.1/sql", process_api01_sql_req, NULL);
 
253
  evhttp_set_gencb(httpd, process_request, NULL);
 
254
 
 
255
  pthread_t libevent_loop_thread;
 
256
 
 
257
  pthread_create(&libevent_loop_thread, NULL, libevent_thread, NULL);
 
258
 
 
259
  return 0;
 
260
}
 
261
 
 
262
static void init_options(drizzled::module::option_context &context)
 
263
{
 
264
  context("port",
 
265
          po::value<port_constraint>(&port)->default_value(80),
 
266
          _("Port number to use for connection or 0 for default (port 80) "));
 
267
}
 
268
 
 
269
} /* namespace json_server */
 
270
} /* namespace drizzle_plugin */
 
271
 
 
272
DRIZZLE_DECLARE_PLUGIN
 
273
{
 
274
  DRIZZLE_VERSION_ID,
 
275
  "json-server",
 
276
  "0.1",
 
277
  "Stewart Smith",
 
278
  "JSON HTTP interface",
 
279
  PLUGIN_LICENSE_GPL,
 
280
  drizzle_plugin::json_server::json_server_init,             /* Plugin Init */
 
281
  NULL, /* depends */
 
282
  drizzle_plugin::json_server::init_options    /* config options */
 
283
}
 
284
DRIZZLE_DECLARE_PLUGIN_END;