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 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. Write your own "controllers"
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
- # We do stuff here
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
- 4. Add 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 :
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(response)
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
- 5. And finally start the component :
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! It's just a proof of concept. Feel free to pull, branch, improve {code|specs|tests|docs} and we will merge it!
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.3 : Not suited for production, use at your own risks
22
- VERSION = '0.0.3'
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
- @stanza = params[:stanza]
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
- "app/views/#{self.class.name.gsub("Controller","").downcase}/#{action_name || @action_name}.xml.builder"
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
@@ -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.to_xml #we return the doc's root (to avoid the instruct)
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
- # callback the controllers to tell them we're connected!
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
@@ -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(connection, stanza)
42
+ def route(stanza)
43
+ return false if !@@connection
29
44
  @routes ||= []
30
45
  @routes.each { |route|
31
- if route.accepts?(connection, stanza)
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
- connection.send(response)
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?(connection, stanza)
89
+ def accepts?(stanza)
74
90
  stanza.xpath(@xpath, stanza.namespaces).first ? self : false
75
91
  end
76
92
 
@@ -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
- def self.run(env = "development")
12
- config = YAML::load(File.new('config/config.yaml'))[env]
13
- routes = YAML::load(File.new('config/routes.yaml')) || []
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 self, stanza
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.to_s
63
+ send_data "#{xml}"
61
64
  end
62
65
 
63
66
  private
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: julien51-babylon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julien Genestoux