Permalink
Browse files

added basic support for describe stanzas

  • Loading branch information...
1 parent 1c43851 commit 3293797a7f20efa44a4cadb1edcc53c933f850dd @flosse committed Jan 5, 2012
Showing with 167 additions and 30 deletions.
  1. +11 −1 README.markdown
  2. +18 −0 lib/Manager.coffee
  3. +3 −0 lib/Parser.coffee
  4. +10 −7 lib/Router.coffee
  5. +17 −0 lib/Serializer.coffee
  6. +11 −6 lib/node-xmpp-joap.coffee
  7. +21 −0 lib/stanza.coffee
  8. +44 −11 spec/Manager.spec.coffee
  9. +32 −5 spec/Serializer.spec.coffee
View
12 README.markdown
@@ -87,5 +87,15 @@ router.on "rpc", (action) ->
## Running tests
```shell
-jasmine-node --coffee --color spec/
+jasmine-node --coffee spec/
```
+
+## ToDo's
+
+- search support
+- Jabber RPC support
+- client library
+
+## License
+
+node-xmpp-joap is licensed under the MIT-Licence (see LICENSE.txt)
View
18 lib/Manager.coffee
@@ -1,12 +1,19 @@
+# This program is distributed under the terms of the MIT license.
+# Copyright 2012 (c) Markus Kohlhase <mail@markus-kohlhase.de>
+
events = require "events"
joap = require "node-xmpp-joap"
class Manager extends events.EventEmitter
constructor: (@xmpp) ->
+
@classes = {}
@objects = {}
+ @serverDescription={'en-US':"JOAP Server"}
+ @serverAttributes = {}
@router = new joap.Router @xmpp
+ @router.on "describe", @onDescribe
@router.on "add", @onAdd
@router.on "read", @onRead
@router.on "edit", @onEdit
@@ -57,6 +64,17 @@ class Manager extends events.EventEmitter
delete @objects[a.class][a.instance]
@router.sendResponse a
+ onDescribe: (a) =>
+ 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
+
# Public method to override by the main application
hasPermission: (action) -> true
View
3 lib/Parser.coffee
@@ -1,3 +1,6 @@
+# This program is distributed under the terms of the MIT license.
+# Copyright 2012 (c) Markus Kohlhase <mail@markus-kohlhase.de>
+
ltx = require "ltx"
joap = require "./node-xmpp-joap"
View
17 lib/Router.coffee
@@ -1,11 +1,10 @@
+# This program is distributed under the terms of the MIT license.
+# Copyright 2012 (c) Markus Kohlhase <mail@markus-kohlhase.de>
+
ltx = require "ltx"
events = require "events"
joap = require "./node-xmpp-joap"
-JOAP_NS = "jabber:iq:joap"
-RPC_NS = "jabber:iq:rpc"
-JOAP_STANZAS = ["describe", "read","add", "edit", "delete", "search"]
-
class Router extends events.EventEmitter
constructor: (@xmpp) ->
@@ -18,10 +17,14 @@ class Router extends events.EventEmitter
if action.type?
to = iq.attrs.to
- action.from = iq.attrs.from
- action.class = to.split('@')[0]
- action.instance = to.split('/')[1]
action.iq = iq
+ action.from = iq.attrs.from
+
+ if to.indexOf('@') >= 0
+ action.class = to.substr(0, to.indexOf '@')
+
+ if to.indexOf('/') >= 0
+ action.instance = to.substr(to.indexOf('/') + 1)
@emit action.type, action
@emit "action", action
View
17 lib/Serializer.coffee
@@ -1,3 +1,6 @@
+# This program is distributed under the terms of the MIT license.
+# Copyright 2012 (c) Markus Kohlhase <mail@markus-kohlhase.de>
+
ltx = require "ltx"
joap = require "./node-xmpp-joap"
@@ -30,6 +33,20 @@ class Serializer
for v in val
el.c("item").t(v.toString()).up()
el
+ when "describe"
+ if val?
+ if val.desc?
+ for k,v of val.desc
+ el.cnode(new joap.Description v,k).up()
+ if val.attributes?
+ for k,v of val.attributes
+ el.cnode(new joap.AttributeDescription k, v.type, v.writable, v.desc).up()
+ if val.classes?
+ for c in val.classes
+ el.c("class").t(c).up()
+ if val.timestamp?
+ el.c("timestamp").t(val.timestamp).up()
+ el
else if action.type is "rpc"
el = (new Element "query", {xmlns:RPC_NS})
View
17 lib/node-xmpp-joap.coffee
@@ -1,14 +1,19 @@
+# This program is distributed under the terms of the MIT license.
+# Copyright 2012 (c) Markus Kohlhase <mail@markus-kohlhase.de>
+
stanza = require("./stanza")
exports.Router = require("./Router").Router
exports.Manager = require("./Manager").Manager
-exports.Attribute = stanza.Attribute
-exports.Member = stanza.Member
-exports.Struct = stanza.Struct
-exports.Array = stanza.Array
-exports.Value = stanza.Value
-exports.ErrorIq = stanza.ErrorIq
+exports.Attribute = stanza.Attribute
+exports.Member = stanza.Member
+exports.Struct = stanza.Struct
+exports.Array = stanza.Array
+exports.Value = stanza.Value
+exports.ErrorIq = stanza.ErrorIq
+exports.Description = stanza.Description
+exports.AttributeDescription = stanza.AttributeDescription
Parser = require("./Parser").Parser
View
21 lib/stanza.coffee
@@ -1,3 +1,6 @@
+# This program is distributed under the terms of the MIT license.
+# Copyright 2012 (c) Markus Kohlhase <mail@markus-kohlhase.de>
+
ltx = require "ltx"
joap = require "./node-xmpp-joap"
JOAP_NS = "jabber:iq:joap"
@@ -15,6 +18,22 @@ class Attribute extends KeyVal
constructor: (key, value) ->
super "attribute", key, value
+class AttributeDescription extends ltx.Element
+
+ constructor: (name, type, writable=true, desc) ->
+ super "attributeDescription", {writable: writable.toString()}
+ @c("name")
+ .t(name.toString()).up()
+ .c("type").t(type).up()
+ if desc?
+ @cnode(new Description v, k) for k,v of desc
+
+class Description extends ltx.Element
+
+ constructor: (text="", lang="en-US") ->
+ super "desc", "xml:lang": lang
+ @t(text)
+
class Member extends KeyVal
constructor: (key, value) ->
@@ -59,6 +78,8 @@ class Error extends ltx.Element
@t msg
exports.Attribute = Attribute
+exports.AttributeDescription = AttributeDescription
+exports.Description = Description
exports.Member = Member
exports.Struct = Struct
exports.Array = Array
View
55 spec/Manager.spec.coffee
@@ -9,16 +9,18 @@ describe "Manager", ->
clientJID = "client@exmaple.tld"
createErrorIq = (type, code, msg, clazz, instance) ->
- from = "#{clazz or 'User'}@#{compJID}"
- from += "/#{instance}" if instance?
+ from = compJID
+ from = "#{clazz}@#{from}" if clazz?
+ from += "/#{instance}" if instance?
errMsg = new joap.ErrorIq type, code, msg,
to: clientJID
from: from
id: "#{type}_id_0"
createRequest = (type, clazz, instance) ->
- to = "#{clazz or 'User'}@#{compJID}"
- to += "/#{instance}" if instance?
+ to = compJID
+ to = "#{clazz}@#{to}" if clazz?
+ to += "/#{instance}" if instance?
iq = new ltx.Element "iq",
to: to
from:clientJID
@@ -55,15 +57,15 @@ describe "Manager", ->
describe "add", ->
- createAddRequest = -> createRequest("add")
+ createAddRequest = (clazz, instance) -> createRequest("add", clazz, instance)
createAddErrorIq = (code, msg, clazz, instance) -> createErrorIq("add", code, msg, clazz, instance)
beforeEach ->
@mgr = new joap.Manager xmppComp
- @request = createAddRequest()
+ @request = createAddRequest "User"
it "returns an error if you are not authorized", ->
- @result = createAddErrorIq '403', "You are not authorized"
+ @result = createAddErrorIq '403', "You are not authorized", "User"
@mgr.hasPermission = -> false
run.call @
@@ -73,20 +75,20 @@ describe "Manager", ->
run.call @
it "returns an error if class doesn't exists", ->
- @result = createAddErrorIq 404, "Class 'User' does not exists"
+ @result = createAddErrorIq 404, "Class 'User' does not exists", "User"
run.call @
it "returns an error if required attributes are not available", ->
class User
@mgr.addClass "User", User, ["name"]
- @result = createAddErrorIq 406, "Invalid constructor parameters"
+ @result = createAddErrorIq 406, "Invalid constructor parameters", "User"
run.call @
it "returns an error if required attributes are not correct", ->
class User
@mgr.addClass "User", User, ["name"]
@request.getChild("add").cnode(new joap.Attribute "age", 33)
- @result = createAddErrorIq 406, "Invalid constructor parameters"
+ @result = createAddErrorIq 406, "Invalid constructor parameters", "User"
run.call @
it "returns the address of the new instance", ->
@@ -260,7 +262,7 @@ describe "Manager", ->
it "returns an error if address is not an instance", ->
@request = createRequest "delete"
- @result = createErrorIq "delete", 405, "'User@#{compJID}' is not an instance"
+ @result = createErrorIq "delete", 405, "'#{compJID}' is not an instance"
run.call @
it "deletes the specified instance", ->
@@ -274,3 +276,34 @@ describe "Manager", ->
(expect users.foo).toBeDefined()
run.call @
(expect users.foo).toBeUndefined()
+
+ describe "describe", ->
+
+ class User
+ constructor: (@name, @age) ->
+ @id = "foo"
+
+ beforeEach ->
+ @mgr = new joap.Manager xmppComp
+ @mgr.addClass "User", User, ["name"], ["id"]
+ @mgr.createClass {class:"User", attributes:{name: "Markus", age:123 }}
+ @request = createRequest "describe"
+
+ it "returns the describtion of the object server", ->
+ serverDesc = "This server manages users"
+ @mgr.serverDescription = { "en-US":serverDesc }
+ @mgr.serverAttributes =
+ x: {type: "int", desc: {"en-US": "a magic number"}, writable: false }
+ @result = new ltx.Element "iq",
+ to:clientJID
+ from:compJID
+ id:'describe_id_0'
+ type:'result'
+ @result.c("describe", {xmlns: JOAP_NS})
+ .c("desc", "xml:lang":'en-US').t(serverDesc).up()
+ .c("attributeDescription", writable:'false')
+ .c("name").t("x").up()
+ .c("type").t("int").up()
+ .c("desc","xml:lang":'en-US').t("a magic number").up().up()
+ .c("class").t("User").up()
+ run.call @
View
37 spec/Serializer.spec.coffee
@@ -26,11 +26,12 @@ describe "Serializer", ->
it "serializes result attributes", ->
- readAct = { type: "read" }
- addAct = { type: "add" }
- editAct = { type: "edit" }
- delAct = { type: "delete" }
- searchAct = { type: "search" }
+ descAct = { type: "describe" }
+ readAct = { type: "read" }
+ addAct = { type: "add" }
+ editAct = { type: "edit" }
+ delAct = { type: "delete" }
+ searchAct = { type: "search" }
addr = "Class@component.example.com/instance"
readObj = {a:"foo", b:2}
@@ -48,6 +49,32 @@ describe "Serializer", ->
(expect Serializer.serialize null, delAct).toEqual ltx.parse "<delete xmlns='jabber:iq:joap' />"
+ serverDesc =
+ desc:
+ "en-US":"A server"
+ "de-DE":"Ein Server"
+ attributes:
+ foo:
+ writable:true
+ type: "bar"
+ desc:
+ "en-US":"Hello world"
+ "de-DE":"Hallo Welt"
+ bar:
+ writable:false
+ type: "int"
+
+ (expect Serializer.serialize serverDesc, descAct).toEqual ltx.parse "<describe xmlns='jabber:iq:joap' >" +
+ "<desc xml:lang='en-US' >A server</desc>"+
+ "<desc xml:lang='de-DE' >Ein Server</desc>"+
+ "<attributeDescription writable='true'><name>foo</name><type>bar</type>" +
+ "<desc xml:lang='en-US' >Hello world</desc>"+
+ "<desc xml:lang='de-DE' >Hallo Welt</desc>"+
+ "</attributeDescription>"+
+ "<attributeDescription writable='false'><name>bar</name><type>int</type>" +
+ "</attributeDescription>"+
+ "</describe>"
+
searchResults = ["a", "b", "c"]
(expect Serializer.serialize searchResults, searchAct).toEqual ltx.parse "<search xmlns='jabber:iq:joap' >" +
"<item>a</item>" +

0 comments on commit 3293797

Please sign in to comment.