diff --git a/api.coffee b/api.coffee index 56ea8b7..63b82c4 100644 --- a/api.coffee +++ b/api.coffee @@ -5,6 +5,7 @@ url = require 'url' db = require './db' mongodb = require 'mongodb' querystring = require 'querystring' +query = require './query' # regular expression objects DEVICE_TASKS_REGEX = /^\/devices\/([a-zA-Z0-9\-\_\%]+)\/tasks\/?$/ @@ -13,6 +14,7 @@ TAGS_REGEX = /^\/devices\/([a-zA-Z0-9\-\_\%]+)\/tags\/([a-zA-Z0-9\-\_\%]+)\/?$/ PRESETS_REGEX = /^\/presets\/([a-zA-Z0-9\-\_\%]+)\/?$/ FILES_REGEX = /^\/files\/([a-zA-Z0-9\-\_\%\ \.\/\(\)]+)\/?$/ PING_REGEX = /^\/ping\/([a-zA-Z0-9\-\_\.]+)\/?$/ +QUERY_REGEX = /^\/([a-zA-Z0-9_]+s)\/?$/ connectionRequest = (deviceId, callback) -> db.devicesCollection.findOne({_id : deviceId}, {'InternetGatewayDevice.ManagementServer.ConnectionRequestURL._value' : 1}, (err, device)-> @@ -280,6 +282,37 @@ else response.writeHead(200, {'Content-Type' : 'text/plain', 'Cache-Control' : 'no-cache'}) response.end(stdout) ) + else if QUERY_REGEX.test(urlParts.pathname) + collectionName = QUERY_REGEX.exec(urlParts.pathname)[1] + if request.method isnt 'GET' + response.writeHead 405, {'Allow' : 'GET'} + response.end('405 Method Not Allowed') + return + collection = db["#{collectionName}Collection"] + if not collection? + response.writeHead 404 + response.end('404 Not Found') + return + + if urlParts.query.query? + q = JSON.parse(querystring.unescape(urlParts.query.query)) + else + q = {} + q = query.expand(q) if collectionName is 'devices' + cur = collection.find(q, {}, {batchSize : 50}) + + cur.skip(parseInt(urlParts.query.skip)) if urlParts.query.skip? + cur.limit(parseInt(urlParts.query.limit)) if urlParts.query.limit? + + response.writeHead(200, {'Content-Type' : 'application/json'}) + response.write("[\n") + cur.each((err, item) -> + if item is null + response.end(']') + else + response.write(JSON.stringify(item) + ",\n") + ) + return else response.writeHead 404 response.end('404 Not Found') diff --git a/config.coffee b/config.coffee index 7d12e23..ec45124 100644 --- a/config.coffee +++ b/config.coffee @@ -16,3 +16,15 @@ exports.MEMCACHED_SOCKET = '/tmp/memcached.sock' exports.WORKER_RESPAWN_TIME = 3000 exports.LOG_INFORMS = false exports.DEBUG_DEVICES = {} # {'202BC1-BM632w-8KA8WA1151100043' : true} + +parameters = require './parameters' +aliases = {} +for k,v of parameters + a = v.alias + if a? + if not aliases[a]? + aliases[a] = [] + aliases[a].push(k) + +exports.PARAMETERS = parameters +exports.ALIASES = aliases diff --git a/normalize.coffee b/normalize.coffee index 1032160..683b7d8 100644 --- a/normalize.coffee +++ b/normalize.coffee @@ -1,11 +1,31 @@ +config = require './config' common = require './common' normalizers = {} +normalizers.default = (input, normType) -> + if normType is 'query' and common.typeOf(input) is common.STRING_TYPE + vals = [] + str = normalizers.string(input, normType) + if common.typeOf(str) == common.ARRAY_TYPE + vals = vals.concat(str) + else + vals.push(str) + + f = parseFloat(input) + if not isNaN(f) + vals.push(f) + + d = new Date(input) + if input.length >= 8 and d.getFullYear() > 1983 + vals.push(d) + return vals + return input + FLOAT_REGEX = /^([\-\+]?[0-9\.]+)/ -normalizers.float = (input) -> +normalizers.float = (input, normType) -> res = FLOAT_REGEX.exec(input) if res != null parseFloat(res[1]) @@ -13,27 +33,19 @@ normalizers.float = (input) -> null -exports.normalize = (path, value) -> - if path of parameters - return normalizers[parameters[path].type](value) +normalizers.date = (input, normType) -> + return new Date(input) + + +normalizers.string = (input, normType) -> + if normType is 'query' + if /^\/(.*?)\/(g?i?m?y?)$/.test(input) + return [{'$regex' : eval(input)}, input] + input + + +exports.normalize = (path, value, normType) -> + if path of config.PARAMETERS + return normalizers[config.PARAMETERS[path].type](value) else - return value - - -parameters = { - 'InternetGatewayDevice.WiMAX.Status.RSSI' : { - type : 'float', - }, - 'InternetGatewayDevice.WiMAX.Status.CINR1' : { - type : 'float', - }, - 'InternetGatewayDevice.WiMAX.Status.CINR2' : { - type : 'float', - }, - 'InternetGatewayDevice.X_MTK_WiMAX_Param.CINR_level' : { - type : 'float', - }, - 'InternetGatewayDevice.X_MTK_WiMAX_Param.RSSI_level' : { - type : 'float', - }, -} \ No newline at end of file + return normalizers['default'](value, normType) diff --git a/parameters.json b/parameters.json new file mode 100644 index 0000000..4fa6023 --- /dev/null +++ b/parameters.json @@ -0,0 +1,21 @@ +{ + "InternetGatewayDevice.WiMAX.Status.RSSI" : { + "alias" : "RSSI", + "type" : "float" + }, + "InternetGatewayDevice.WiMAX.Status.CINR1" : { + "alias" : "CINR", + "type" : "float" + }, + "InternetGatewayDevice.WiMAX.Status.CINR2" : { + "type" : "float" + }, + "InternetGatewayDevice.X_MTK_WiMAX_Param.CINR_level" : { + "alias" : "CINR", + "type" : "float" + }, + "InternetGatewayDevice.X_MTK_WiMAX_Param.RSSI_level" : { + "alias" : "RSSI", + "type" : "float" + } +} \ No newline at end of file diff --git a/query.coffee b/query.coffee new file mode 100644 index 0000000..aa34d5a --- /dev/null +++ b/query.coffee @@ -0,0 +1,86 @@ +config = require './config' +common = require './common' +normalize = require './normalize' + + +expandValue = (param, value) -> + if common.typeOf(value) is common.ARRAY_TYPE + a = [] + for j in value + a = a.concat(expandValue(param, j)) + return [a] + else if common.typeOf(value) isnt common.OBJECT_TYPE + n = normalize.normalize(param, value, 'query') + if common.typeOf(n) isnt common.ARRAY_TYPE + return [n] + else + return n + + objs = [] + indices = [] + keys = [] + values = [] + for k,v of value + keys.push(k) + values.push(expandValue(param, v)) + indices.push(0) + + i = 0 + while i < indices.length + obj = {} + for i in [0...keys.length] + obj[keys[i]] = values[i][indices[i]] + objs.push(obj) + + for i in [0...indices.length] + indices[i] += 1 + if indices[i] < values[i].length + break + indices[i] = 0 + return objs + + +permute = (param, val) -> + keys = [] + if config.ALIASES[param]? + for p in config.ALIASES[param] + keys.push(p) + else + keys.push(param) + + conditions = [] + for k in keys + values = expandValue(k, val) + if k[k.lastIndexOf('.') + 1] != '_' + k += '._value' + + for v in values + obj = {} + obj[k] = v + conditions.push(obj) + + return conditions + + +expand = (query) -> + new_query = {} + for k,v of query + if k[0] == '$' # operator + expressions = [] + for e in v + expressions.push(expand(e)) + new_query[k] = expressions + else + conditions = permute(k, v) + if conditions.length > 1 + if new_query['$and']? + new_query['$and'].push({'$or' : conditions}) + else + new_query['$and'] = [{'$or' : conditions}] + else + common.extend(new_query, conditions[0]) + + return new_query + + +exports.expand = expand