jacs 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Dirk Gadsden
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,9 @@
1
+ = jacs
2
+
3
+ === What is it?
4
+
5
+ A super-simple way to establish a client-server system using Jabber/XMPP. The protocol is heavily inspired by HTTP. (It even uses HTTP path formatting and status codes!)
6
+
7
+ === Copyright
8
+
9
+ Copyright (c) 2010 Dirk Gadsden. See LICENSE for details.
@@ -0,0 +1,86 @@
1
+ module ActionJabber
2
+ class Base
3
+ class << self
4
+ @@routes = []
5
+ def route(path, opts = {}, &block)
6
+ @@routes << [path, opts, block]
7
+ end
8
+ def route!(request)
9
+ @@request = request
10
+ @@routes.each do |route|
11
+ if route.first == request.path
12
+ instance_eval do
13
+ result = route.last.call
14
+ self.reset!
15
+ return result
16
+ end
17
+ end
18
+ end
19
+ end
20
+ def request
21
+ @@request
22
+ end
23
+ def reset!
24
+ @@request = nil
25
+ end
26
+ end
27
+ end
28
+ class Server
29
+ def initialize(username, password, controller)
30
+ @jabber = Jabber::Simple.new(username, password)
31
+ @controller = controller # Should be a class.
32
+ end
33
+ def run!
34
+ while @jabber.connected?
35
+ @jabber.received_messages do |message|
36
+ start = Time.now
37
+
38
+ from = message.from.to_s.split('/').first
39
+ parts = message.body.strip.split(':', 2)
40
+ hash = parts.first
41
+ path_parts = parts.last.split('?', 2)
42
+ request = Request.new(hash, from, path_parts.first, ((path_parts.length == 2) ? path_parts.last : ''))
43
+ begin
44
+ #process_message(message.from.to_s.strip, message.body.strip)
45
+ response = {:status => 200, :data => ''}.merge @controller.route!(request)
46
+ #response = @controller.route! request
47
+ respond_to request, :status => response[:status], :data => response[:data]
48
+ rescue
49
+ respond_to request, :status => 500
50
+ puts "Error responding to #{message.from.to_s.strip}:"
51
+ puts $!
52
+ else
53
+ puts "Responded to '#{from}' in #{(Time.now - start).to_s} seconds."
54
+ end
55
+ puts "\n"
56
+ end
57
+ end
58
+ end
59
+ def respond_to(request, opts = {})
60
+ from = request.from
61
+ status = opts[:status] or 200
62
+ data = opts[:data] or ''
63
+ resp = "#{request.hash}:#{opts[:status]}"
64
+ unless data.to_s.empty?
65
+ resp += (':' + data.to_s)
66
+ end
67
+ @jabber.deliver(Jabber::JID.new(request.from), resp)
68
+ end
69
+
70
+ class Request
71
+ attr_reader :hash, :format, :from, :path, :args
72
+
73
+ def initialize(hash, from, path, args)
74
+ @hash = hash
75
+ @from = from
76
+ @path = path
77
+ begin
78
+ @format = path.match(/\.([A-z]+)$/).to_a[1].to_sym
79
+ rescue
80
+ @format = nil
81
+ end
82
+ @args = args
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,109 @@
1
+ module ActiveJabber
2
+ class Base
3
+ def jabber
4
+ if @jabber
5
+ if @jabber.connected?
6
+ return @jabber
7
+ else
8
+ @jabber.reconnect
9
+ end
10
+ else
11
+ @jabber = Jabber::Simple.new(@username, @password)
12
+ end
13
+ return @jabber
14
+ end
15
+ def initialize(username, password)
16
+ @username = username
17
+ @password = password
18
+ end
19
+ def method_missing(method, *args)
20
+ request_parts = []
21
+ Base::Request.new(self, nil, request_parts).send(method, *args)
22
+ end
23
+ def request(path, opts)
24
+ hash = self.generate_hash
25
+ message = hash + ':' + path.gsub(/\?$/, '')
26
+ if opts[:args]
27
+ message += ('?' + opts[:args])
28
+ end
29
+ unless opts[:timeout]
30
+ opts[:timeout] = 5.0
31
+ end
32
+
33
+ self.jabber.deliver(Jabber::JID.new('accounts@madelike.com'), message)
34
+ start = Time.now
35
+ while (Time.now - start) < opts[:timeout]
36
+ self.jabber.received_messages do |msg|
37
+ if msg.body.strip.starts_with?(hash) and msg.from.to_s.strip.starts_with?('accounts@madelike.com')
38
+ parts = msg.body.strip.split(':', 3)
39
+ data = (parts[2].nil? ? '' : parts[2].strip)
40
+ if opts[:format] == :json
41
+ data = ActiveSupport::JSON.decode(data)
42
+ end
43
+ response = {:status => parts[1].to_i, :data => data}
44
+ response[:latency] = (Time.now - start)
45
+ return response
46
+ end
47
+ end
48
+ end
49
+ if (Time.now - start) >= opts[:timeout]
50
+ return {:status => 408, :data => '', :latency => (Time.now - start)} # Request timeout
51
+ end
52
+ end
53
+ def generate_hash
54
+ ActiveSupport::SecureRandom.hex(8) # Generates 16 character hexdecimal string.
55
+ end
56
+
57
+ class Request
58
+ attr_accessor :parts
59
+
60
+ def initialize(base, part, parts)
61
+ @base = base
62
+ @parts = parts
63
+ unless part.nil?
64
+ @parts << ('/' + part.to_s)
65
+ end
66
+ end
67
+ def parse_format(method)
68
+ if method.to_s == 'json' or method.to_s == 'json?'
69
+ :json
70
+ elsif method.to_s == 'text' or method.to_s == 'text?'
71
+ :text
72
+ end
73
+ end
74
+ def method_missing(method, *args)
75
+ if args.length > 0 or self.parse_format(method) or method.to_s.ends_with? '!'
76
+ format = self.parse_format(method)
77
+ opts = {
78
+ :format => (format or :text),
79
+ :args => ''
80
+ }
81
+ if (args.second.is_a? Hash or args.second.nil?) and format == :json
82
+ if args.first
83
+ opts[:args] = (args.first.is_a?(String) ? args.first : args.first.to_json)
84
+ end
85
+ if args.second
86
+ opts.merge! args.second
87
+ end
88
+ elsif args.first.is_a? Hash
89
+ opts.merge! args.first
90
+ elsif args.first.respond_to? :to_s
91
+ opts[:args] = args.first.to_s
92
+ if args.second.is_a? Hash
93
+ opts.merge! args.second
94
+ end
95
+ end
96
+ if format == :json
97
+ @parts << '.json'
98
+ else
99
+ @parts << ('/' + method.to_s.gsub(/!$/, ''))
100
+ end
101
+
102
+ @base.request(@parts.join(''), opts)
103
+ else
104
+ Request.new(@base, method, @parts)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
data/lib/jacs.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'active_support'
2
+ require 'xmpp4r-simple'
3
+
4
+ # Little utility to make me less insane.
5
+ class Array
6
+ def second
7
+ self[1]
8
+ end
9
+ end
10
+
11
+ require File.dirname(__FILE__) + '/activejabber'
12
+ require File.dirname(__FILE__) + '/actionjabber'
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jacs
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Dirk Gadsden
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-05-14 00:00:00 -04:00
17
+ default_executable:
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: xmpp4r-simple
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 0
28
+ - 8
29
+ - 8
30
+ version: 0.8.8
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 2
42
+ - 3
43
+ - 5
44
+ version: 2.3.5
45
+ type: :runtime
46
+ version_requirements: *id002
47
+ description: Simple, distributed client-server communication using Jabber/XMPP.
48
+ email: dirk@esherido.com
49
+ executables: []
50
+
51
+ extensions: []
52
+
53
+ extra_rdoc_files:
54
+ - LICENSE
55
+ - README.rdoc
56
+ files:
57
+ - lib/jacs.rb
58
+ - lib/actionjabber.rb
59
+ - lib/activejabber.rb
60
+ - LICENSE
61
+ - README.rdoc
62
+ has_rdoc: true
63
+ homepage: http://esherido.com/
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project:
88
+ rubygems_version: 1.3.6
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Client-server communication using Jabber/XMPP.
92
+ test_files: []
93
+