julien51-babylon 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +37 -11
- data/lib/babylon.rb +2 -2
- data/lib/babylon/base/controller.rb +6 -3
- data/lib/babylon/base/view.rb +1 -1
- data/lib/babylon/component_connection.rb +2 -3
- data/lib/babylon/router.rb +20 -4
- data/lib/babylon/runner.rb +7 -3
- data/lib/babylon/xmpp_connection.rb +6 -3
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -21,38 +21,64 @@ Babylon is a framework to EventMachine based XMPP External Components in Ruby.
|
|
21
21
|
|
22
22
|
$> babylon myapp
|
23
23
|
|
24
|
-
3.
|
24
|
+
3. Use the generator or write your own controllers :
|
25
|
+
|
26
|
+
$> scripts/generate message echo:10:"//message[@type='chat']/body" subscribed:0:"//presence[@type='subscribe']"
|
27
|
+
|
28
|
+
This will generate a "MessageController" class with 2 methods : echo and subscribed. "echo" will be called when the component receives message stanzas of type 'chat', while "subscribed" will be called for presence stanzas of type 'subscribe'. 10 and 0 are the priority : useful when a stanza matches 2 XPath. Also, try to put high priorities to the "most frequent" stanzas to improve your component's performance. This will also generate 2 'views' used to build your stanzas. And finally, this will write 2 routes in the config/routes.yaml
|
29
|
+
|
30
|
+
4. Write your application's code and views :
|
25
31
|
|
26
32
|
/app/controllers/message_controller.rb
|
27
33
|
|
28
|
-
class MessageController < Babylon::Base::Controller
|
29
|
-
# Each controller is initiated with the stanza.(similar to params in rails actions)
|
34
|
+
class MessageController < Babylon::Base::Controller
|
30
35
|
|
31
36
|
def echo
|
32
|
-
|
37
|
+
extract_to_and_from
|
38
|
+
body = @stanza.xpath("//message/body").first
|
39
|
+
@resp = body.text.reverse
|
40
|
+
end
|
41
|
+
|
42
|
+
def subscribed
|
43
|
+
extract_to_and_from
|
44
|
+
@ack = "Thanks for following me!"
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def extract_to_and_from
|
50
|
+
@from = @stanza.attributes["to"].text
|
33
51
|
@to = @stanza.attributes["from"].text
|
34
|
-
@from = @stanza.attributes["from"].text
|
35
|
-
@response = @stanza.elements["//body"].text
|
36
|
-
# By default, this would "render" the echo.xml.builder
|
37
52
|
end
|
53
|
+
|
38
54
|
end
|
55
|
+
|
39
56
|
|
40
|
-
|
57
|
+
5. Implement the corresponding views (used to generate the messages). Babylon uses the same file conventions as Rails : a subdirectory for each controller, and one file per action :
|
41
58
|
Compared to Rails, we are using accessors (and not @variables assigned in the controller).
|
42
59
|
|
43
60
|
/app/views/message/echo.xml.builder
|
44
61
|
|
45
62
|
self.message(:to => to, :from => from, :type => :chat) do
|
46
|
-
self.body(
|
63
|
+
self.body(resp)
|
64
|
+
end
|
65
|
+
|
66
|
+
/app/views/message/subscribed.xml.builder
|
67
|
+
|
68
|
+
self.message(:to => to, :from => from, :type => :chat) do
|
69
|
+
self.body(ack) # Same as self.send(:body, body)
|
47
70
|
end
|
48
71
|
|
49
|
-
|
72
|
+
6. Make sure that the XMPP settings are correct in config/config.yaml. !!! You need to have a Jabber Component, regular clients will NOT work!!!
|
73
|
+
|
74
|
+
|
75
|
+
7. And finally start the component :
|
50
76
|
|
51
77
|
script/component
|
52
78
|
|
53
79
|
== ADDITIONAL INFORMATION
|
54
80
|
|
55
|
-
This code hasn't been tested at all!
|
81
|
+
This code hasn't been tested at all! (yes, i know it's bad, but I couldn't have rspec working with eventmachine) Feel free to pull, branch, improve {code|specs|tests|docs} and we will merge it!
|
56
82
|
|
57
83
|
== REQUIREMENTS:
|
58
84
|
|
data/lib/babylon.rb
CHANGED
@@ -18,7 +18,7 @@ require 'babylon/base/view'
|
|
18
18
|
# This will generate some folders and files for your application. Please see README for further instructions
|
19
19
|
|
20
20
|
module Babylon
|
21
|
-
# 0.0.
|
22
|
-
VERSION = '0.0.
|
21
|
+
# 0.0.4 : Not suited for production, use at your own risks
|
22
|
+
VERSION = '0.0.4'
|
23
23
|
end
|
24
24
|
|
@@ -9,7 +9,9 @@ module Babylon
|
|
9
9
|
|
10
10
|
# Creates a new controller (you should not override this class) and assigns the stanza
|
11
11
|
def initialize(params = {})
|
12
|
-
|
12
|
+
params.each do |key, value|
|
13
|
+
instance_variable_set("@#{key}", value)
|
14
|
+
end
|
13
15
|
@rendered = false
|
14
16
|
end
|
15
17
|
|
@@ -30,7 +32,7 @@ module Babylon
|
|
30
32
|
elsif action_name = options[:action]
|
31
33
|
return render(:file => default_template_name(action_name.to_s))
|
32
34
|
end
|
33
|
-
render_for_file(options[:file])
|
35
|
+
render_for_file(File.join("app/views", "#{self.class.name.gsub("Controller","").downcase}", options[:file]))
|
34
36
|
|
35
37
|
# And finally, we set up rendered to be true
|
36
38
|
@rendered = true
|
@@ -49,7 +51,8 @@ module Babylon
|
|
49
51
|
|
50
52
|
# Default template name used to build stanzas
|
51
53
|
def default_template_name(action_name = nil)
|
52
|
-
"
|
54
|
+
path = "#{action_name || @action_name}.xml.builder"
|
55
|
+
return path
|
53
56
|
end
|
54
57
|
|
55
58
|
# Creates the view and "evaluates" it to build the XML for the stanza
|
data/lib/babylon/base/view.rb
CHANGED
@@ -22,7 +22,7 @@ module Babylon
|
|
22
22
|
xml = Nokogiri::XML::Builder.new do
|
23
23
|
instance_eval(view_content)
|
24
24
|
end
|
25
|
-
return xml.doc.root
|
25
|
+
return xml.doc.root #we return the doc's root (to avoid the instruct)
|
26
26
|
end
|
27
27
|
|
28
28
|
##
|
@@ -33,9 +33,8 @@ module Babylon
|
|
33
33
|
|
34
34
|
when :wait_for_handshake
|
35
35
|
if stanza.name == "handshake"
|
36
|
-
# Awesome, we're now connected and authentified, let's
|
37
|
-
|
38
|
-
# TODO
|
36
|
+
# Awesome, we're now connected and authentified, let's tell the CentralRouter we're connecter
|
37
|
+
CentralRouter.connected(self)
|
39
38
|
@state = :connected
|
40
39
|
else
|
41
40
|
raise
|
data/lib/babylon/router.rb
CHANGED
@@ -4,6 +4,8 @@ module Babylon
|
|
4
4
|
# The router is in charge of sending the right stanzas to the right controllers based on user defined Routes.
|
5
5
|
module Router
|
6
6
|
|
7
|
+
@@connection = nil
|
8
|
+
|
7
9
|
##
|
8
10
|
# Add several routes to the router
|
9
11
|
# Routes should be of form {name => params}
|
@@ -13,6 +15,18 @@ module Babylon
|
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
18
|
+
##
|
19
|
+
# Connected is called by the XmppConnection to indicate that the XMPP connection has been established
|
20
|
+
def connected(connection)
|
21
|
+
@@connection = connection
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Accessor for @@connection
|
26
|
+
def connection
|
27
|
+
@@connection
|
28
|
+
end
|
29
|
+
|
16
30
|
##
|
17
31
|
# Insert a route and makes sure that the routes are sorted
|
18
32
|
def add_route(route)
|
@@ -25,14 +39,16 @@ module Babylon
|
|
25
39
|
|
26
40
|
# Look for the first martching route and calls the correspondong action for the corresponding controller.
|
27
41
|
# Sends the response on the XMPP stream/
|
28
|
-
def route(
|
42
|
+
def route(stanza)
|
43
|
+
return false if !@@connection
|
29
44
|
@routes ||= []
|
30
45
|
@routes.each { |route|
|
31
|
-
if route.accepts?(
|
46
|
+
if route.accepts?(stanza)
|
32
47
|
# Here should happen the magic : call the controller
|
33
48
|
controller = route.controller.new({:stanza => stanza})
|
34
49
|
controller.perform(route.action) do |response|
|
35
|
-
|
50
|
+
# Response should be a Nokogiri::Node Object
|
51
|
+
@@connection.send(response)
|
36
52
|
end
|
37
53
|
return true
|
38
54
|
end
|
@@ -70,7 +86,7 @@ module Babylon
|
|
70
86
|
|
71
87
|
##
|
72
88
|
# Checks that the route matches the stanzas and calls the the action on the controller
|
73
|
-
def accepts?(
|
89
|
+
def accepts?(stanza)
|
74
90
|
stanza.xpath(@xpath, stanza.namespaces).first ? self : false
|
75
91
|
end
|
76
92
|
|
data/lib/babylon/runner.rb
CHANGED
@@ -8,9 +8,10 @@ module Babylon
|
|
8
8
|
# When run is called, it loads the configuration, the routes and add them into the router
|
9
9
|
# It then loads the models.
|
10
10
|
# Finally it starts the EventMachine and connect the ComponentConnection
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
# You can pass an additional block that will be called upon launching, when the eventmachine has been started.
|
12
|
+
def self.run(env = "development", &callback)
|
13
|
+
config = YAML::load(File.new('config/config.yaml'))[env]
|
14
|
+
routes = YAML::load(File.new('config/routes.yaml')) || []
|
14
15
|
|
15
16
|
# Adding Routes
|
16
17
|
CentralRouter.add_routes(routes)
|
@@ -24,6 +25,9 @@ module Babylon
|
|
24
25
|
EventMachine.epoll
|
25
26
|
EventMachine::run do
|
26
27
|
Babylon::ComponentConnection.connect(config)
|
28
|
+
|
29
|
+
# And finally, let's allow the application to do all it wants to do after we started the EventMachine!
|
30
|
+
callback.call if callback
|
27
31
|
end
|
28
32
|
end
|
29
33
|
|
@@ -36,7 +36,7 @@ module Babylon
|
|
36
36
|
def receive_stanza(stanza)
|
37
37
|
puts "<< #{stanza}\n" if debug? # Low level Logging
|
38
38
|
# If not handled by subclass (for authentication)
|
39
|
-
CentralRouter.route
|
39
|
+
CentralRouter.route stanza
|
40
40
|
end
|
41
41
|
|
42
42
|
##
|
@@ -54,10 +54,13 @@ module Babylon
|
|
54
54
|
end
|
55
55
|
|
56
56
|
##
|
57
|
-
# Sends data (string) on the stream. Eventually it displays this data for debugging purposes
|
57
|
+
# Sends the Nokogiri::XML data (after converting to string) on the stream. It also appends the right "from" to be the component's JId if none has been mentionned. Eventually it displays this data for debugging purposes
|
58
58
|
def send(xml)
|
59
|
+
if !xml.attributes["from"]
|
60
|
+
xml["from"] = config['jid']
|
61
|
+
end
|
59
62
|
puts ">> #{xml}\n" if debug? # Very low level Logging
|
60
|
-
send_data xml
|
63
|
+
send_data "#{xml}"
|
61
64
|
end
|
62
65
|
|
63
66
|
private
|