Permalink
Browse files

added support for search queries

  • Loading branch information...
1 parent e73f6d0 commit 7b47c622e6dc0d930c6f70f8936dac12450fefc7 @flosse committed Jan 7, 2012
Showing with 95 additions and 20 deletions.
  1. +6 −0 Cakefile
  2. +22 −3 README.markdown
  3. +62 −15 lib/Manager.coffee
  4. +5 −2 lib/Router.coffee
View
@@ -0,0 +1,6 @@
+{exec} = require 'child_process'
+
+task 'test', "runnig tests", ->
+ exec "jasmine-node --coffee spec/", (err, out) ->
+ console.log err if err?
+ console.log out
View
@@ -53,6 +53,7 @@ nStore = require "nstore"
# create database
users = nStore.new './data/users.db', (err) ->
+
if err?
console.error err
else
@@ -72,6 +73,16 @@ users = nStore.new './data/users.db', (err) ->
next new Error "Storage for this class is not available"
# override
+ mgr.queryInstances = (clazz, attrs, next) ->
+ if clazz is "User"
+ next = attrs; attrs = null if typeof attrs is "function"
+ if attrs?
+ @users.find attrs, (err, res) -> next err, (id for id of res)
+ else @users.all (err, res) -> next err, (id for id of res)
+ else
+ next new Error "Storage for this class is not available"
+
+ # override
mgr.deleteInstance = (clazz, id, next) ->
if clazz is "User"
users.remove id, next
@@ -114,6 +125,8 @@ router.on "add", (action) ->
# ...
+router.on "search", (action) ->
+
router.on "rpc", (action) ->
console.log "calling #{action.method} with:"
for param in actions.params
@@ -122,15 +135,21 @@ router.on "rpc", (action) ->
## Running tests
+[jasmine-node](https://github.com/mhevery/jasmine-node)
+is required (`npm install -g jasmine-node`) for running the tests.
+
```shell
-jasmine-node --coffee spec/
+cake test
```
+## JOAP client implementations
+
+- [strophe.js plugin](https://github.com/metajack/strophejs-plugins/tree/master/joap)
+
## ToDo's
-- search support
+- describe support
- Jabber RPC support
-- client library
## License
View
@@ -12,12 +12,14 @@ class Manager extends events.EventEmitter
@classes = {}
@serverDescription={'en-US':"JOAP Server"}
@serverAttributes = {}
+ @serverMethods = {}
@router = new joap.Router @xmpp
@router.on "describe", @onDescribe
@router.on "add", @onAdd
@router.on "read", @onRead
@router.on "edit", @onEdit
@router.on "delete", @onDelete
+ @router.on "search", @onSearch
@objects = {}
@getArgNames: (fn) ->
@@ -40,6 +42,9 @@ class Manager extends events.EventEmitter
# override if you want to manipule the description of instances
describe: (a, callback) -> callback null, a
+ # override if you want to manipule the search of instances
+ search: (a, callback) -> callback null, a
+
# override if you want to use a database
saveInstance: (clazz, id, obj, next) ->
@objects[clazz][id] = obj
@@ -49,6 +54,19 @@ class Manager extends events.EventEmitter
loadInstance: (clazz, id, next) -> next null, @objects[clazz][id]
# override if you want to use a database
+ queryInstances: (clazz, attrs, next) ->
+ if typeof attrs is "function"
+ next = attrs
+ attrs = null
+ if attrs?
+ items = []
+ for id, o of @objects[clazz]
+ items.push id for k,v of attrs when o[k] is v
+ next null, items
+ else
+ next null, (k for k,v of @objects[clazz])
+
+ # override if you want to use a database
deleteInstance: (clazz, id, next) ->
delete @objects[clazz][id]
next null
@@ -69,7 +87,14 @@ class Manager extends events.EventEmitter
x = new clazz.creator (a.attributes[n] for n in argNames when n isnt "")...
x.id = joap.uniqueId() if not x.id
@saveInstance a.class, x.id, x, (err) =>
- next err, "#{a.class}@#{@router.xmpp.jid}/#{x.id}"
+ next err, @getAddress a.class, x.id
+
+ getAddress: (clazz, instance) ->
+ addr = ""
+ addr += "#{clazz}@" if clazz if typeof clazz is "string"
+ addr += @router.xmpp.jid
+ addr += "/#{instance}" if typeof instance is "string"
+ addr
onRead: (a) =>
if @grant(a) and @classExists(a)
@@ -101,6 +126,7 @@ class Manager extends events.EventEmitter
onEdit: (a) =>
if @grant(a)
+ #TODO: Is it possible to edit the server attributes?
@instanceExists a, (err, exists) =>
if exists and not err? and @areWritableAttributes(a)
@before.edit a, (err, a) =>
@@ -133,20 +159,41 @@ class Manager extends events.EventEmitter
@router.sendResponse a
onDescribe: (a) =>
- @before.describe a, (err, a) =>
- if err?
- @sendInternalServerError a
- else
- data = null
- if not a.class?
- data = desc: @serverDescription
- classes = (k for k,v of @classes)
- if classes.length > 0
- data.classes = classes
- data.attributes = @serverAttributes
-
- @router.sendResponse a, data
-
+ if @grant(a)
+ @before.describe a, (err, a) =>
+ if err?
+ @sendInternalServerError a
+ else
+ data = null
+ if not a.class?
+ data = desc: @serverDescription
+ data.attributes = @serverAttributes
+ #TODO: Implement class descriptions
+ # data.methods = @getMethodDescriptions @serverMethods
+ classes = (k for k,v of @classes)
+ data.classes = classes if classes.length > 0
+ @router.sendResponse a, data
+
+ #TODO: Implement class descriptions
+ # else if a.class? and not a.instance?
+
+ #TODO: Implement object descriptions
+ # else if a.class? and a.instance?
+
+ else
+ @sendInternalServerError a
+
+ onSearch: (a) =>
+ if @grant(a) and @isClassAddress(a) and @classExists(a)
+ @before.search a, (err, a) =>
+ if err?
+ @sendInternalServerError a
+ else
+ @queryInstances a.class, a.attributes, (err, items) =>
+ if err? or not items?
+ @sendInternalServerError a
+ else
+ @router.sendResponse a, (@getAddress a.class, id for id in items)
grant: (a) ->
if not @hasPermission a
View
@@ -26,8 +26,11 @@ class Router extends events.EventEmitter
if to.indexOf('/') >= 0
action.instance = to.substr(to.indexOf('/') + 1)
- @emit action.type, action
- @emit "action", action
+ if typeof action.type is "string" and action.type.trim() isnt ""
+ @emit action.type, action
+ @emit "action", action
+ else
+ @sendError action, 406, "stanza #{action.type} is not supported"
sendError: (a, code, msg) ->
@send new joap.ErrorIq a.type, code, msg,

0 comments on commit 7b47c62

Please sign in to comment.