| 1 | #include <libmemcached/memcached.h> |
|---|
| 2 | #include <v8.h> |
|---|
| 3 | #include <cstring> |
|---|
| 4 | #include <string> |
|---|
| 5 | #include "v8ext.h" |
|---|
| 6 | #include "llv8-util.h" |
|---|
| 7 | |
|---|
| 8 | using namespace v8; |
|---|
| 9 | |
|---|
| 10 | static inline memcached_st * _memc(const Arguments& args) { |
|---|
| 11 | return handle<memcached_st>(args, 0); |
|---|
| 12 | } |
|---|
| 13 | |
|---|
| 14 | inline static Handle<Value> throw_exception(memcached_st * memc, memcached_return rc, const char*funcname) { |
|---|
| 15 | std::string str("Memcached Error("); |
|---|
| 16 | str += funcname; |
|---|
| 17 | str += "): "; |
|---|
| 18 | str += memcached_strerror(memc, rc); |
|---|
| 19 | return ThrowException(String::New(str.c_str())); |
|---|
| 20 | } |
|---|
| 21 | |
|---|
| 22 | static Handle<Value> _new(const Arguments& args) { |
|---|
| 23 | HandleScope handle_scope; |
|---|
| 24 | |
|---|
| 25 | memcached_st *memc = memcached_create(NULL);; |
|---|
| 26 | args.This()->SetInternalField(0, External::New((void*)memc)); |
|---|
| 27 | return args.This(); |
|---|
| 28 | } |
|---|
| 29 | |
|---|
| 30 | static Handle<Value> _server_add(const Arguments& args) { |
|---|
| 31 | if (args.Length() != 2) { |
|---|
| 32 | return ThrowException(String::New("Exception: missing args: server_add(host, port)")); |
|---|
| 33 | } |
|---|
| 34 | |
|---|
| 35 | HandleScope handle_scope; |
|---|
| 36 | memcached_return rc; |
|---|
| 37 | memcached_st *memc = _memc(args); |
|---|
| 38 | |
|---|
| 39 | String::AsciiValue host(args[0]); |
|---|
| 40 | |
|---|
| 41 | rc = memcached_server_add(memc, *host, args[1]->Int32Value()); |
|---|
| 42 | if (rc != MEMCACHED_SUCCESS) { |
|---|
| 43 | return throw_exception(memc, rc, "server_add"); |
|---|
| 44 | } |
|---|
| 45 | return Undefined(); |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| 48 | static Handle<Value> _behavior_set(const Arguments& args) { |
|---|
| 49 | if (args.Length() != 2) { |
|---|
| 50 | return ThrowException(String::New("Exception: missing args: BehaviorSet(flag, data)")); |
|---|
| 51 | } |
|---|
| 52 | if (args[0]->IsUndefined()) { |
|---|
| 53 | return ThrowException(String::New("Exception: invalid args: args[0] should not be undefined.")); |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | HandleScope handle_scope; |
|---|
| 57 | memcached_return rc; |
|---|
| 58 | memcached_st *memc = _memc(args); |
|---|
| 59 | |
|---|
| 60 | rc = memcached_behavior_set(memc, memcached_behavior(args[0]->Int32Value()), args[1]->Int32Value()); |
|---|
| 61 | if (rc != MEMCACHED_SUCCESS) { |
|---|
| 62 | return throw_exception(memc, rc, "behavior_set"); |
|---|
| 63 | } |
|---|
| 64 | return Undefined(); |
|---|
| 65 | } |
|---|
| 66 | |
|---|
| 67 | static Handle<Value> _behavior_get(const Arguments& args) { |
|---|
| 68 | if (args.Length() != 1) { |
|---|
| 69 | return ThrowException(String::New("Exception: missing args: BehaviorGet(flag)")); |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | HandleScope handle_scope; |
|---|
| 73 | memcached_return rc; |
|---|
| 74 | memcached_st *memc = _memc(args); |
|---|
| 75 | |
|---|
| 76 | uint64_t data = (uint64_t)( |
|---|
| 77 | memcached_behavior_get(memc, memcached_behavior(args[0]->Int32Value())) |
|---|
| 78 | ); |
|---|
| 79 | return Integer::New(data); |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | static Handle<Value> _get(const Arguments& args) { |
|---|
| 83 | if (args.Length() != 1) { |
|---|
| 84 | return ThrowException(String::New("Exception: missing args: get(key)")); |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | HandleScope handle_scope; |
|---|
| 88 | memcached_return rc; |
|---|
| 89 | memcached_st *memc = _memc(args); |
|---|
| 90 | uint32_t flags; |
|---|
| 91 | size_t value_length; |
|---|
| 92 | |
|---|
| 93 | String::AsciiValue key(args[0]); |
|---|
| 94 | char * value = memcached_get(memc, *key, strlen(*key), |
|---|
| 95 | &value_length, &flags, &rc); |
|---|
| 96 | if (rc == MEMCACHED_NOTFOUND) { |
|---|
| 97 | return Undefined(); |
|---|
| 98 | } else if (rc == MEMCACHED_SUCCESS) { |
|---|
| 99 | Handle<Object> res = Object::New(); |
|---|
| 100 | res->Set(String::New("value"), String::New(value, value_length)); |
|---|
| 101 | res->Set(String::New("flags"), Integer::New(flags)); |
|---|
| 102 | free(value); |
|---|
| 103 | return res; |
|---|
| 104 | } else { |
|---|
| 105 | return throw_exception(memc, rc, "get"); |
|---|
| 106 | } |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | static Handle<Value> _set(const Arguments& args) { |
|---|
| 110 | if (args.Length() != 4) { |
|---|
| 111 | return ThrowException(String::New("Exception: missing args: set(key, val, expiration, flags)")); |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | HandleScope handle_scope; |
|---|
| 115 | memcached_st *memc = _memc(args); |
|---|
| 116 | |
|---|
| 117 | String::AsciiValue key(args[0]); |
|---|
| 118 | String::AsciiValue val(args[1]); |
|---|
| 119 | time_t expiration = args[2]->Uint32Value(); |
|---|
| 120 | uint32_t flags = args[3]->Uint32Value(); |
|---|
| 121 | |
|---|
| 122 | memcached_return rc = memcached_set( |
|---|
| 123 | memc, |
|---|
| 124 | *key, args[0]->ToString()->Length(), |
|---|
| 125 | *val, args[1]->ToString()->Length(), |
|---|
| 126 | expiration, |
|---|
| 127 | flags |
|---|
| 128 | ); |
|---|
| 129 | if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) { |
|---|
| 130 | return throw_exception(memc, rc, "set"); |
|---|
| 131 | } else { |
|---|
| 132 | return Undefined(); |
|---|
| 133 | } |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | static Handle<Value> _del(const Arguments& args) { |
|---|
| 137 | if (args.Length() != 1) { |
|---|
| 138 | return ThrowException(String::New("Exception: missing args: del(key)")); |
|---|
| 139 | } |
|---|
| 140 | |
|---|
| 141 | HandleScope handle_scope; |
|---|
| 142 | memcached_st *memc = _memc(args); |
|---|
| 143 | |
|---|
| 144 | String::AsciiValue key(args[0]); |
|---|
| 145 | time_t expiration = args[1]->Uint32Value(); |
|---|
| 146 | memcached_return rc = memcached_delete( |
|---|
| 147 | memc, |
|---|
| 148 | *key, args[0]->ToString()->Length(), |
|---|
| 149 | expiration |
|---|
| 150 | ); |
|---|
| 151 | if (rc == MEMCACHED_SUCCESS) { |
|---|
| 152 | return Undefined(); |
|---|
| 153 | } else { |
|---|
| 154 | return throw_exception(memc, rc, "del"); |
|---|
| 155 | } |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | static Handle<Value> _increment(const Arguments& args) { |
|---|
| 159 | if (args.Length() != 2) { |
|---|
| 160 | return ThrowException(String::New("Exception: missing args: incr(key, offset)")); |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | HandleScope handle_scope; |
|---|
| 164 | memcached_st *memc = _memc(args); |
|---|
| 165 | |
|---|
| 166 | String::AsciiValue key(args[0]); |
|---|
| 167 | uint32_t offset = args[1]->Uint32Value(); |
|---|
| 168 | uint64_t buf; |
|---|
| 169 | |
|---|
| 170 | memcached_return rc = memcached_increment( |
|---|
| 171 | memc, |
|---|
| 172 | *key, args[0]->ToString()->Length(), |
|---|
| 173 | offset, |
|---|
| 174 | &buf |
|---|
| 175 | ); |
|---|
| 176 | if (rc != MEMCACHED_SUCCESS) { |
|---|
| 177 | return throw_exception(memc, rc, "increment"); |
|---|
| 178 | } else { |
|---|
| 179 | return Integer::New(buf); |
|---|
| 180 | } |
|---|
| 181 | } |
|---|
| 182 | |
|---|
| 183 | static Handle<Value> _decrement(const Arguments& args) { |
|---|
| 184 | if (args.Length() != 2) { |
|---|
| 185 | return ThrowException(String::New("Exception: missing args: decrement(key, offset)")); |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | HandleScope handle_scope; |
|---|
| 189 | memcached_st *memc = _memc(args); |
|---|
| 190 | |
|---|
| 191 | String::AsciiValue key(args[0]); |
|---|
| 192 | uint32_t offset = args[1]->Uint32Value(); |
|---|
| 193 | uint64_t buf; |
|---|
| 194 | |
|---|
| 195 | memcached_return rc = memcached_decrement( |
|---|
| 196 | memc, |
|---|
| 197 | *key, args[0]->ToString()->Length(), |
|---|
| 198 | offset, |
|---|
| 199 | &buf |
|---|
| 200 | ); |
|---|
| 201 | if (rc != MEMCACHED_SUCCESS) { |
|---|
| 202 | return throw_exception(memc, rc, "decrement"); |
|---|
| 203 | } else { |
|---|
| 204 | return Integer::New(buf); |
|---|
| 205 | } |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | static Handle<Value> _lib_version(const Arguments& args) { |
|---|
| 209 | HandleScope handle_scope; |
|---|
| 210 | return String::New(memcached_lib_version()); |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | static Handle<Value> _ServerCount(const Arguments& args) { |
|---|
| 214 | HandleScope handle_scope; |
|---|
| 215 | memcached_st* memc = _memc(args); |
|---|
| 216 | unsigned int i = memcached_server_count(memc); |
|---|
| 217 | return Int32::New(i); |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | static Handle<Value> _Stat(const Arguments& args) { |
|---|
| 221 | HandleScope handle_scope; |
|---|
| 222 | memcached_st* memc = _memc(args); |
|---|
| 223 | memcached_return rc; |
|---|
| 224 | memcached_stat_st * stat = memcached_stat(memc, NULL, &rc); |
|---|
| 225 | if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS) { |
|---|
| 226 | return throw_exception(memc, rc, "stat"); |
|---|
| 227 | } |
|---|
| 228 | memcached_server_st * server_list = memcached_server_list(memc); |
|---|
| 229 | Handle<Array> res = Array::New(); |
|---|
| 230 | for (int i=0; i<memcached_server_count(memc); i++) { |
|---|
| 231 | char **list = memcached_stat_get_keys(memc, &stat[i], &rc); |
|---|
| 232 | Handle<Object> row = Object::New(); |
|---|
| 233 | for (char **ptr = list; *ptr; ptr++) { |
|---|
| 234 | memcached_return rc; |
|---|
| 235 | char *value= memcached_stat_get_value(memc, &stat[i], *ptr, &rc); |
|---|
| 236 | row->Set(String::New(*ptr), String::New(value)); |
|---|
| 237 | free(value); |
|---|
| 238 | } |
|---|
| 239 | res->Set(Int32::New(i), row); |
|---|
| 240 | free(list); |
|---|
| 241 | } |
|---|
| 242 | free(stat); |
|---|
| 243 | return res; |
|---|
| 244 | } |
|---|
| 245 | |
|---|
| 246 | static Handle<Value> _free(const Arguments& args) { |
|---|
| 247 | HandleScope handle_scope; |
|---|
| 248 | memcached_st* memc = _memc(args); |
|---|
| 249 | memcached_free(memc); |
|---|
| 250 | return Undefined(); |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | extern "C" V8EXTINIT_FUNC |
|---|
| 254 | void init_lib(Handle<Object>obj) { |
|---|
| 255 | HandleScope scope; |
|---|
| 256 | |
|---|
| 257 | Handle<FunctionTemplate> ft = FunctionTemplate::New(_new); |
|---|
| 258 | ft->Set("LibVersion", String::New(memcached_lib_version())); |
|---|
| 259 | // generated by: |
|---|
| 260 | // perl -ne 'print qq{ft->Set("$2", Int32::New($1));\n} if /(MEMCACHED_(BEHAVIOR.+)),/' /opt/local/include/libmemcached/memcached_constants.h |
|---|
| 261 | ft->Set("BEHAVIOR_NO_BLOCK", Int32::New(MEMCACHED_BEHAVIOR_NO_BLOCK)); |
|---|
| 262 | ft->Set("BEHAVIOR_TCP_NODELAY", Int32::New(MEMCACHED_BEHAVIOR_TCP_NODELAY)); |
|---|
| 263 | ft->Set("BEHAVIOR_HASH", Int32::New(MEMCACHED_BEHAVIOR_HASH)); |
|---|
| 264 | ft->Set("BEHAVIOR_KETAMA", Int32::New(MEMCACHED_BEHAVIOR_KETAMA)); |
|---|
| 265 | ft->Set("BEHAVIOR_SOCKET_SEND_SIZE", Int32::New(MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE)); |
|---|
| 266 | ft->Set("BEHAVIOR_SOCKET_RECV_SIZE", Int32::New(MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE)); |
|---|
| 267 | ft->Set("BEHAVIOR_CACHE_LOOKUPS", Int32::New(MEMCACHED_BEHAVIOR_CACHE_LOOKUPS)); |
|---|
| 268 | ft->Set("BEHAVIOR_SUPPORT_CAS", Int32::New(MEMCACHED_BEHAVIOR_SUPPORT_CAS)); |
|---|
| 269 | ft->Set("BEHAVIOR_POLL_TIMEOUT", Int32::New(MEMCACHED_BEHAVIOR_POLL_TIMEOUT)); |
|---|
| 270 | ft->Set("BEHAVIOR_DISTRIBUTION", Int32::New(MEMCACHED_BEHAVIOR_DISTRIBUTION)); |
|---|
| 271 | ft->Set("BEHAVIOR_BUFFER_REQUESTS", Int32::New(MEMCACHED_BEHAVIOR_BUFFER_REQUESTS)); |
|---|
| 272 | ft->Set("BEHAVIOR_USER_DATA", Int32::New(MEMCACHED_BEHAVIOR_USER_DATA)); |
|---|
| 273 | ft->Set("BEHAVIOR_SORT_HOSTS", Int32::New(MEMCACHED_BEHAVIOR_SORT_HOSTS)); |
|---|
| 274 | ft->Set("BEHAVIOR_VERIFY_KEY", Int32::New(MEMCACHED_BEHAVIOR_VERIFY_KEY)); |
|---|
| 275 | ft->Set("BEHAVIOR_CONNECT_TIMEOUT", Int32::New(MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT)); |
|---|
| 276 | ft->Set("BEHAVIOR_RETRY_TIMEOUT", Int32::New(MEMCACHED_BEHAVIOR_RETRY_TIMEOUT)); |
|---|
| 277 | ft->Set("BEHAVIOR_KETAMA_WEIGHTED", Int32::New(MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED)); |
|---|
| 278 | ft->Set("BEHAVIOR_KETAMA_HASH", Int32::New(MEMCACHED_BEHAVIOR_KETAMA_HASH)); |
|---|
| 279 | ft->Set("BEHAVIOR_BINARY_PROTOCOL", Int32::New(MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)); |
|---|
| 280 | ft->Set("BEHAVIOR_SND_TIMEOUT", Int32::New(MEMCACHED_BEHAVIOR_SND_TIMEOUT)); |
|---|
| 281 | ft->Set("BEHAVIOR_RCV_TIMEOUT", Int32::New(MEMCACHED_BEHAVIOR_RCV_TIMEOUT)); |
|---|
| 282 | |
|---|
| 283 | Handle<ObjectTemplate> ot = ft->InstanceTemplate(); |
|---|
| 284 | |
|---|
| 285 | ot->Set("ServerAdd", FunctionTemplate::New(_server_add)); |
|---|
| 286 | ot->Set("BehaviorSet", FunctionTemplate::New(_behavior_set)); |
|---|
| 287 | ot->Set("BehaviorGet", FunctionTemplate::New(_behavior_get)); |
|---|
| 288 | ot->Set("Get", FunctionTemplate::New(_get)); |
|---|
| 289 | ot->Set("Set", FunctionTemplate::New(_set)); |
|---|
| 290 | ot->Set("Del", FunctionTemplate::New(_del)); |
|---|
| 291 | ot->Set("Increment", FunctionTemplate::New(_increment)); |
|---|
| 292 | ot->Set("Decrement", FunctionTemplate::New(_decrement)); |
|---|
| 293 | ot->Set("Free", FunctionTemplate::New(_free)); |
|---|
| 294 | ot->Set("ServerCount", FunctionTemplate::New(_ServerCount)); |
|---|
| 295 | ot->Set("Stat", FunctionTemplate::New(_Stat)); |
|---|
| 296 | |
|---|
| 297 | ot->SetInternalFieldCount(1); |
|---|
| 298 | obj->Set( |
|---|
| 299 | String::New("Memcached"), |
|---|
| 300 | ft->GetFunction() |
|---|
| 301 | ); |
|---|
| 302 | } |
|---|
| 303 | |
|---|