├── README.md ├── .gitignore ├── demo.js ├── package.json └── SSDB.js /README.md: -------------------------------------------------------------------------------- 1 | nodessdb 2 | ======== 3 | 4 | SSDB nodejs client 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.class 4 | .DS_Store 5 | *.pyc 6 | *.swp 7 | *_cpy_* 8 | 9 | -------------------------------------------------------------------------------- /demo.js: -------------------------------------------------------------------------------- 1 | var SSDB = require('./SSDB.js'); 2 | var ssdb = SSDB.connect(host, port); 3 | 4 | ssdb.set('a', new Date(), function(){ 5 | console.log('set a'); 6 | }); 7 | ssdb.get('a', function(err, val){ 8 | console.log('get a = ' + val); 9 | ssdb.close(); 10 | }); 11 | 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodessdb", 3 | "version": "1.0.0", 4 | "description": "SSDB nodejs Client", 5 | "main": "SSDB.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/ssdb/nodessdb.git" 12 | }, 13 | "keywords": [ 14 | "foo", 15 | "bar" 16 | ], 17 | "author": "ideawu", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/ssdb/nodessdb/issues" 21 | }, 22 | "homepage": "https://github.com/ssdb/nodessdb#readme" 23 | } 24 | -------------------------------------------------------------------------------- /SSDB.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013, ideawu 3 | * All rights reserved. 4 | * @author: ideawu 5 | * @link: http://www.ideawu.com/ 6 | * 7 | * SSDB nodejs client SDK. 8 | */ 9 | 10 | var net = require('net'); 11 | 12 | // timeout: microseconds, if ommitted, it will be treated as listener 13 | // callback(err, ssdb) 14 | exports.connect = function(host, port, timeout, listener){ 15 | var self = this; 16 | var recv_buf = new Buffer(0); 17 | var callbacks = []; 18 | var connected = false; 19 | 20 | if(typeof(timeout) == 'function'){ 21 | listener = timeout; 22 | timeout = 0; 23 | } 24 | timeout = timeout || 0; 25 | listener = listener || function(){}; 26 | 27 | var sock = new net.Socket(); 28 | sock.on('error', function(e){ 29 | if(!connected){ 30 | listener('connect_failed', e); 31 | }else{ 32 | var callback = callbacks.shift(); 33 | callback(['error']); 34 | } 35 | }); 36 | sock.connect(port, host, function(){ 37 | connected = true; 38 | sock.setNoDelay(true); 39 | sock.setKeepAlive(true); 40 | sock.setTimeout(timeout); 41 | listener(0, self); 42 | }); 43 | 44 | self.close = function(){ 45 | sock.end(); 46 | } 47 | 48 | self.request = function(cmd, params, callback){ 49 | callbacks.push(callback || function(){}); 50 | var arr = [cmd].concat(params); 51 | self.send_request(arr); 52 | } 53 | 54 | function build_buffer(arr){ 55 | var bs = []; 56 | var size = 0; 57 | for(var i = 0; i < arr.length; i++){ 58 | var arg = arr[i]; 59 | if(arg instanceof Buffer){ 60 | // 61 | }else{ 62 | arg = new Buffer(arg.toString()); 63 | } 64 | bs.push(arg); 65 | size += arg.length; 66 | } 67 | var ret = new Buffer(size); 68 | var offset = 0; 69 | for(var i=0; i 0){ 101 | var resp = parse(); 102 | if(!resp){ 103 | break; 104 | } 105 | resp[0] = resp[0].toString(); 106 | var callback = callbacks.shift(); 107 | callback(resp); 108 | } 109 | }); 110 | 111 | function memchr(buf, ch, start){ 112 | start = start || 0; 113 | ch = typeof(ch) == 'string'? ch.charCodeAt(0) : ch; 114 | for(var i=start; i recv_buf.length){ 150 | // not finished 151 | //console.log(spos + len, recv_buf.length); 152 | //console.log('not finish'); 153 | return null; 154 | } 155 | //var data = recv_buf.substr(spos, len); 156 | var data = recv_buf.slice(spos, spos + len); 157 | spos += len; 158 | ret.push(data); 159 | 160 | //pos = recv_buf.indexOf('\n', spos); 161 | pos = memchr(recv_buf, '\n', spos); 162 | if(pos == -1){ 163 | // not finished 164 | console.log('error 3'); 165 | return null; 166 | } 167 | // '\n', or '\r\n' 168 | //if(recv_buf.charAt(spos) != '\n' && recv_buf.charAt(spos) != '\r' && recv_buf.charAt(spos+1) != '\n'){ 169 | var cr = '\r'.charCodeAt(0); 170 | var lf = '\n'.charCodeAt(0); 171 | if(recv_buf[spos] != lf && recv_buf[spos] != cr && recv_buf[spos+1] != lf){ 172 | // error 173 | console.log('error 4 ' + recv_buf[spos]); 174 | return null; 175 | } 176 | spos = pos + 1; 177 | } 178 | return ret; 179 | } 180 | 181 | // callback(err, val); 182 | // err: 0 on sucess, or error_code(string) on error 183 | self.get = function(key, callback){ 184 | self.request('get', [key], function(resp){ 185 | if(callback){ 186 | var err = resp[0] == 'ok'? 0 : resp[0]; 187 | var val = resp[1]; 188 | callback(err, val); 189 | } 190 | }); 191 | } 192 | 193 | // callback(err); 194 | self.set = function(key, val, callback){ 195 | self.request('set', [key, val], function(resp){ 196 | if(callback){ 197 | var err = resp[0] == 'ok'? 0 : resp[0]; 198 | callback(err); 199 | } 200 | }); 201 | } 202 | 203 | // callback(err); 204 | self.setx = function(key, val, ttl, callback){ 205 | self.request('setx', [key, val, ttl], function(resp){ 206 | if(callback){ 207 | var err = resp[0] == 'ok'? 0 : resp[0]; 208 | callback(err, resp[1].toString()); 209 | } 210 | }); 211 | } 212 | 213 | // callback(err); 214 | self.ttl = function(key, callback){ 215 | self.request('ttl', [key], function(resp){ 216 | if(callback){ 217 | var err = resp[0] == 'ok'? 0 : resp[0]; 218 | callback(err,resp[1].toString()); 219 | } 220 | }); 221 | } 222 | 223 | // callback(err); 224 | self.del = function(key, callback){ 225 | self.request('del', [key], function(resp){ 226 | if(callback){ 227 | var err = resp[0] == 'ok'? 0 : resp[0]; 228 | callback(err); 229 | } 230 | }); 231 | } 232 | 233 | // callback(err, {index:[], items:{key:score}}) 234 | self.scan = function(key_start, key_end, limit, callback){ 235 | self.request('scan', [key_start, key_end, limit], function(resp){ 236 | if(callback){ 237 | var err = resp[0] == 'ok'? 0 : resp[0]; 238 | if(resp.length % 2 != 1){ 239 | callback('error'); 240 | }else{ 241 | var data = {index: [], items: {}}; 242 | for(var i=1; i