Created
September 11, 2010 19:53
-
-
Save co3k/575491 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
INSTALL:: | |
$ apxs2 -c mod_doyagawa.c -ltokyocabinet -ljansson | |
$ libtool --mode=install cp mod_doyagawa.la $PWD | |
Restful API Interface:: | |
Get Feed: GET http://example.com/doya | |
Get Entry: GET http://example.com/doya/{id} | |
Post Entry: POST http://example.com/doya | |
Put Entry: [Not supported] | |
Delete Entry: [Not supported] | |
JSON Format:: | |
[ | |
{ "x" : 20, "y" : 10, "opacity" : 1.0, "size" : 10, "string" : "doya" }, | |
] | |
TODO: | |
* Getting entry outputs multiple formated doya | |
* Image | |
* Tumbneil | |
* So I think find image generator (supported embbedding font) | |
*/ | |
#include <tcutil.h> | |
#include <tctdb.h> | |
#include <jansson.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <time.h> | |
#include "httpd.h" | |
#include "http_config.h" | |
#include "http_protocol.h" | |
#include "ap_config.h" | |
static char *doyagawa_get_post_data(request_rec *r) | |
{ | |
apr_bucket_brigade *bb; | |
int is_eos = 0; | |
char *body = ""; | |
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); | |
do | |
{ | |
apr_bucket *bucket; | |
apr_status_t rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); | |
for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb); bucket = APR_BUCKET_NEXT(bucket)) | |
{ | |
if (APR_BUCKET_IS_EOS(bucket)) | |
{ | |
is_eos = 1; | |
break; | |
} | |
if (bucket->length != 0) | |
{ | |
const char *data; | |
apr_size_t len; | |
rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); | |
body = apr_pstrcat(r->pool, body, data, NULL); | |
break; | |
} | |
} | |
apr_brigade_cleanup(bb); | |
} | |
while (!is_eos); | |
return body; | |
} | |
static int doyagawa_get_doyas(request_rec *r, TCTDB *db) | |
{ | |
TCXSTR *result; | |
const char *rbuf; | |
int i, rsiz; | |
TDBQRY *q; | |
TCLIST *s; | |
TCMAP *cols; | |
result = tcxstrnew(); | |
tcxstrcat2(result, "["); | |
q = tctdbqrynew(db); | |
tctdbqrysetorder(q, "created_at", TDBQOSTRDESC); | |
tctdbqrysetlimit(q, 10, 0); | |
s = tctdbqrysearch(q); | |
for (i = 0; i < tclistnum(s); i++) { | |
if (i > 0) | |
{ | |
tcxstrcat2(result, ","); | |
} | |
rbuf = tclistval(s, i, &rsiz); | |
cols = tctdbget(db, rbuf, rsiz); | |
if (cols) { | |
tcxstrcat2(result, "["); | |
tcxstrcat2(result, rbuf); | |
tcxstrcat2(result, ","); | |
tcxstrcat2(result, tcmapget2(cols, "json")); | |
tcxstrcat2(result, "]"); | |
} | |
tcmapdel(cols); | |
} | |
tcxstrcat2(result, "]"); | |
ap_rputs((char *)tcxstrptr(result), r); | |
tcxstrdel(result); | |
tclistdel(s); | |
tctdbqrydel(q); | |
return 1; | |
} | |
static int doyagawa_get_doya(request_rec *r, TCTDB *db, const char *pk) | |
{ | |
TCXSTR *result; | |
int i, res; | |
TCMAP *cols; | |
res = 1; | |
result = tcxstrnew(); | |
cols = tctdbget(db, pk, strlen(pk)); | |
if (cols) | |
{ | |
tcxstrcat2(result, "["); | |
tcxstrcat2(result, pk); | |
tcxstrcat2(result, ","); | |
tcxstrcat2(result, tcmapget2(cols, "json")); | |
tcxstrcat2(result, "]"); | |
} | |
tcmapdel(cols); | |
ap_rputs((char *)tcxstrptr(result), r); | |
tcxstrdel(result); | |
return res; | |
} | |
static int doyagawa_post_doya(request_rec *r, TCTDB *db) | |
{ | |
int result = 1, pksiz, i; | |
char pkbuf[256], ut[256]; | |
const char *rbuf, *str; | |
TCMAP *cols; | |
json_t *root; | |
json_error_t error; | |
root = json_loads(doyagawa_get_post_data(r), &error); | |
if (!root || !json_is_array(root)) | |
{ | |
return 0; | |
} | |
for (i = 0; i < json_array_size(root); i++) | |
{ | |
json_t *obj; | |
obj = json_array_get(root, i); | |
if (!json_is_object(obj)) | |
{ | |
return 0; | |
} | |
const char *key; | |
json_t *value; | |
void *iter = json_object_iter(obj); | |
while (iter) | |
{ | |
key = json_object_iter_key(iter); | |
if (0 != strcmp("x", key) && 0 != strcmp("y", key) | |
&& 0 != strcmp("opacity", key) && 0 != strcmp("string", key) | |
&& 0 != strcmp("size", key)) | |
{ | |
json_object_del(obj, key); | |
} | |
iter = json_object_iter_next(obj, iter); | |
} | |
} | |
str = json_dumps(root, JSON_ENSURE_ASCII); | |
pksiz = sprintf(pkbuf, "%ld", (long)tctdbgenuid(db)); | |
sprintf(ut, "%d", (int)time(NULL)); | |
cols = tcmapnew3("json", str, "created_at", ut, NULL); | |
if (tctdbput(db, pkbuf, pksiz, cols)) | |
{ | |
ap_rputs(str, r); | |
} | |
else | |
{ | |
result = 0; | |
} | |
tcmapdel(cols); | |
return result; | |
} | |
static void doyagawa_apply_allowed_method_list(ap_method_list_t *l) | |
{ | |
/* initialize default list */ | |
ap_clear_method_list(l); | |
ap_method_list_add(l, "GET"); | |
ap_method_list_add(l, "POST"); | |
ap_method_list_add(l, "HEAD"); | |
} | |
static int doyagawa_handler(request_rec *r) | |
{ | |
TCTDB *db; | |
const char *pk; | |
int result; | |
if (strcmp(r->handler, "doyagawa")) | |
{ | |
return DECLINED; | |
} | |
r->content_type = "application/json"; | |
db = tctdbnew(); | |
result = OK; | |
if (!tctdbopen(db, "/tmp/example.tct", TDBOWRITER | TDBOCREAT)) | |
{ | |
return HTTP_INTERNAL_SERVER_ERROR; | |
} | |
if (!r->header_only) | |
{ | |
switch (r->method_number) | |
{ | |
case M_GET: | |
if (tcregexmatch(r->uri, "^.*/doya/?$")) | |
{ | |
if (!doyagawa_get_doyas(r, db)) | |
{ | |
result = HTTP_INTERNAL_SERVER_ERROR; | |
} | |
} | |
else if (pk = tcregexreplace(r->uri, "^.*/doya/([0-9]+)/?$", "\\1")) | |
{ | |
if (0 == strcmp(pk, r->uri)) | |
{ | |
result = HTTP_NOT_FOUND; | |
} | |
else if (!doyagawa_get_doya(r, db, pk)) | |
{ | |
result = HTTP_NOT_FOUND; | |
} | |
} | |
else | |
{ | |
result = HTTP_NOT_FOUND; | |
} | |
break; | |
case M_POST: | |
if (!doyagawa_post_doya(r, db)) | |
{ | |
result = HTTP_INTERNAL_SERVER_ERROR; | |
} | |
break; | |
default: | |
doyagawa_apply_allowed_method_list(r->allowed_methods); | |
result = HTTP_METHOD_NOT_ALLOWED; | |
} | |
} | |
if (!tctdbclose(db)) | |
{ | |
result = HTTP_INTERNAL_SERVER_ERROR; | |
} | |
tctdbdel(db); | |
return result; | |
} | |
static void doyagawa_register_hooks(apr_pool_t *p) | |
{ | |
ap_hook_handler(doyagawa_handler, NULL, NULL, APR_HOOK_MIDDLE); | |
} | |
/* Dispatch list for API hooks */ | |
module AP_MODULE_DECLARE_DATA doyagawa_module = | |
{ | |
STANDARD20_MODULE_STUFF, | |
NULL, /* create per-dir config structures */ | |
NULL, /* merge per-dir config structures */ | |
NULL, /* create per-server config structures */ | |
NULL, /* merge per-server config structures */ | |
NULL, /* table of config file commands */ | |
doyagawa_register_hooks /* register hooks */ | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment