sipatra 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,301 @@
1
+ require 'sipatra/helpers'
2
+ require 'sipatra/extension_modules'
3
+ require 'benchmark'
4
+
5
+ module Sipatra
6
+ VERSION = '1.0.0'
7
+
8
+ class Base
9
+ include HelperMethods
10
+ attr_accessor :sip_factory, :context, :session, :msg, :params
11
+
12
+ def initialize()
13
+ @params = Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
14
+ end
15
+
16
+ # called from Java to set SIP servlet bindings
17
+ def set_bindings(*args)
18
+ @context, @sip_factory, @session, @msg = args
19
+ session.extend Sipatra::SessionExtension
20
+ msg.extend Sipatra::MessageExtension
21
+ end
22
+
23
+ def session=(session)
24
+ @session = session
25
+ class << @session
26
+ include SessionExtension
27
+ end
28
+ end
29
+
30
+ # called to process a SIP request
31
+ def do_request
32
+ call! self.class.req_handlers
33
+ end
34
+
35
+ # called to process a SIP response
36
+ def do_response
37
+ call! self.class.resp_handlers
38
+ end
39
+
40
+ # Exit the current block, halts any further processing
41
+ # of the message.
42
+ # TODO: handle a response (as param)
43
+ def halt
44
+ throw :halt
45
+ end
46
+
47
+ # Pass control to the next matching handler.
48
+ def pass
49
+ throw :pass
50
+ end
51
+
52
+ def request?
53
+ !msg.respond_to?(:getRequest)
54
+ end
55
+
56
+ def response?
57
+ msg.respond_to?(:getRequest)
58
+ end
59
+
60
+ private
61
+
62
+ def msg_type
63
+ response? ? :response : :request
64
+ end
65
+
66
+ def eval_options(opts)
67
+ opts.each_pair { |key, condition|
68
+ pass unless header? key
69
+ header_match = condition.match header[key]
70
+ @params[key] = header_match.to_a if header_match
71
+ }
72
+ end
73
+
74
+ def eval_condition(arg, keys, opts)
75
+ #clear (for multi usage)
76
+ @params.clear
77
+ if request?
78
+ match = arg.match msg.requestURI.to_s
79
+ if match
80
+ eval_options(opts)
81
+ if keys.any?
82
+ values = match.captures.to_a #Array of matched values
83
+ keys.zip(values).each do |(k, v)|
84
+ @params[k] = v
85
+ end
86
+ elsif(match.length > 1)
87
+ @params[:uri] = match.to_a
88
+ end
89
+ return true
90
+ end
91
+ else
92
+ if ((arg == 0) or (arg == msg.status))
93
+ eval_options(opts)
94
+ return true
95
+ end
96
+ end
97
+ return false
98
+ end
99
+
100
+ def process_handler(handlers_hash, method_or_joker)
101
+ if handlers = handlers_hash[method_or_joker]
102
+ handlers.each do |pattern, keys, opts, block|
103
+ catch :pass do
104
+ throw :pass unless eval_condition(pattern, keys, opts)
105
+ throw :halt, instance_eval(&block)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # Run all filters defined on superclasses and then those on the current class.
112
+ def filter!(type, base = self.class)
113
+ filter! type, base.superclass if base.superclass.respond_to?(:filters)
114
+ base.filters[type].each { |block| instance_eval(&block) }
115
+ end
116
+
117
+ def call!(handlers)
118
+ filter! :before
119
+ catch(:halt) do
120
+ process_handler(handlers, msg.method)
121
+ process_handler(handlers, "_")
122
+ end
123
+ ensure
124
+ filter! :after
125
+ end
126
+
127
+ class << self
128
+ attr_reader :req_handlers, :resp_handlers, :filters
129
+
130
+ # permits configuration of the application
131
+ def configure(*envs, &block)
132
+ yield self if envs.empty? || envs.include?(environment.to_sym)
133
+ end
134
+
135
+ # Methods defined in the block and/or in the module
136
+ # arguments available to handlers.
137
+ def helpers(*modules, &block)
138
+ include(*modules) if modules.any?
139
+ class_eval(&block) if block_given?
140
+ end
141
+
142
+ # Extension modules registered on this class and all superclasses.
143
+ def extensions
144
+ if superclass.respond_to?(:extensions)
145
+ (@extensions + superclass.extensions).uniq
146
+ else
147
+ @extensions
148
+ end
149
+ end
150
+
151
+ # Extends current class with all modules passed as arguements
152
+ # if a block is present, creates a module with the block and
153
+ # extends the current class with it.
154
+ def register_extension(*extensions, &block)
155
+ extensions << Module.new(&block) if block_given?
156
+ @extensions += extensions
157
+ extensions.each do |extension|
158
+ extend extension
159
+ extension.registered(self) if extension.respond_to?(:registered)
160
+ end
161
+ end
162
+
163
+ def response(*args, &block)
164
+ method_name = args.shift if (!args.first.kind_of? Hash) and (!args.first.kind_of? Integer)
165
+ code_int = args.shift if !args.first.kind_of? Hash
166
+ opts = *args
167
+ pattern = code_int || 0
168
+ sip_method_name = method_name ? method_name.to_s.upcase : "_"
169
+ handler("response_#{sip_method_name} \"#{pattern}\"", sip_method_name, pattern, [], opts || {}, &block)
170
+ end
171
+
172
+ [:ack, :bye, :cancel, :info, :invite, :message,
173
+ :notify, :options, :prack, :publish, :refer,
174
+ :register, :subscribe, :update, :request].each do |name|
175
+ define_method name do |*args, &block|
176
+ path = args.shift if (!args.first.kind_of? Hash)
177
+ opts = *args
178
+ uri = path || //
179
+ pattern, keys = compile_uri_pattern(uri)
180
+ sip_method_name = name == :request ? "_" : name.to_s.upcase
181
+ handler("request_#{sip_method_name} \"#{uri.kind_of?(Regexp) ? uri.source : uri}\"", sip_method_name, pattern, keys , opts || {}, &block)
182
+ end
183
+ end
184
+
185
+ def before(msg_type = nil, &block)
186
+ add_filter(:before, msg_type, &block)
187
+ end
188
+
189
+ def after(msg_type = nil, &block)
190
+ add_filter(:after, msg_type, &block)
191
+ end
192
+
193
+ def reset!
194
+ @req_handlers = {}
195
+ @resp_handlers = {}
196
+ @extensions = []
197
+ @filters = {:before => [], :after => []}
198
+ end
199
+
200
+ def inherited(subclass)
201
+ subclass.reset!
202
+ super
203
+ end
204
+
205
+ def before_filters
206
+ filters[:before]
207
+ end
208
+
209
+ def after_filters
210
+ filters[:after]
211
+ end
212
+
213
+ private
214
+
215
+ def add_filter(type, message_type = nil, &block)
216
+ if message_type
217
+ add_filter(type) do
218
+ next unless msg_type == message_type
219
+ instance_eval(&block)
220
+ end
221
+ else
222
+ filters[type] << block
223
+ end
224
+ end
225
+
226
+ # compiles a URI pattern
227
+ def compile_uri_pattern(uri)
228
+ keys = []
229
+ if uri.respond_to? :to_str
230
+ pattern =
231
+ uri.to_str.gsub(/\(:(\w+)\)/) do |match|
232
+ keys << $1.dup
233
+ "([^:@;=?&]+)"
234
+ end
235
+ [/^#{pattern}$/, keys]
236
+ elsif uri.respond_to? :match
237
+ [uri, keys]
238
+ else
239
+ raise TypeError, uri
240
+ end
241
+ end
242
+
243
+ def handler(method_name, verb, pattern, keys, options={}, &block)
244
+ define_method method_name, &block
245
+ unbound_method = instance_method(method_name)
246
+ block =
247
+ if block.arity != 0
248
+ proc { unbound_method.bind(self).call(*@block_params) }
249
+ else
250
+ proc { unbound_method.bind(self).call }
251
+ end
252
+ handler_table(method_name, verb).push([pattern, keys, options, block]).last # TODO: conditions
253
+ end
254
+
255
+ def handler_table(method_name, verb)
256
+ if method_name.start_with? "response"
257
+ (@resp_handlers ||= {})[verb] ||= []
258
+ else
259
+ (@req_handlers ||= {})[verb] ||= []
260
+ end
261
+ end
262
+ end
263
+
264
+ reset!
265
+ end
266
+
267
+ class Application < Base
268
+ def self.register_extension(*extensions, &block) #:nodoc:
269
+ added_methods = extensions.map {|m| m.public_instance_methods }.flatten
270
+ Delegator.delegate(*added_methods)
271
+ super(*extensions, &block)
272
+ end
273
+ end
274
+
275
+ module Delegator #:nodoc:
276
+ def self.delegate(*methods)
277
+ methods.each do |method_name|
278
+ eval <<-RUBY, binding, '(__DELEGATE__)', 1
279
+ def #{method_name}(*args, &b)
280
+ ::Sipatra::Application.send(#{method_name.inspect}, *args, &b)
281
+ end
282
+ private #{method_name.inspect}
283
+ RUBY
284
+ end
285
+ end
286
+
287
+ delegate :ack, :bye, :cancel, :info, :invite, :message,
288
+ :notify, :options, :prack, :publish, :refer,
289
+ :register, :subscribe, :update,
290
+ :helpers, :configure,
291
+ :before, :after, :request, :response
292
+ end
293
+
294
+ def self.helpers(*extensions, &block)
295
+ Application.helpers(*extensions, &block)
296
+ end
297
+
298
+ def self.register_extension(*extensions, &block)
299
+ Application.register_extension(*extensions, &block)
300
+ end
301
+ end
Binary file
@@ -0,0 +1,21 @@
1
+ module Sipatra
2
+ module MessageExtension
3
+ def uri
4
+ requestURI
5
+ end
6
+ end
7
+
8
+ module SessionExtension
9
+ def [](name)
10
+ getAttribute(name.to_s)
11
+ end
12
+
13
+ def []=(name, value)
14
+ if value.nil?
15
+ removeAttribute(name.to_s)
16
+ else
17
+ setAttribute(name.to_s, value)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,205 @@
1
+ module Sipatra
2
+ STATUS_CODES_MAP = {
3
+ :accepted => 202,
4
+ :address_incomplete => 484,
5
+ :alternative_service => 380,
6
+ :ambiguous => 485,
7
+ :bad_event => 489,
8
+ :bad_extension => 420,
9
+ :bad_gateway => 502,
10
+ :bad_identity_info => 436,
11
+ :bad_request => 400,
12
+ :busy_everywhere => 600,
13
+ :busy_here => 486,
14
+ :call_being_forwarded => 181,
15
+ :call_leg_done => 481,
16
+ :call_queued => 182,
17
+ :conditional_request_failed => 412,
18
+ :decline => 603,
19
+ :does_not_exit_anywhere => 604,
20
+ :extension_required => 421,
21
+ :forbidden => 403,
22
+ :gone => 410,
23
+ :interval_too_brief => 423,
24
+ :invalid_identity_header => 438,
25
+ :loop_detected => 482,
26
+ :message_too_large => 513,
27
+ :method_not_allowed => 405,
28
+ :moved_permanently => 301,
29
+ :moved_temporarily => 302,
30
+ :multiple_choices => 300,
31
+ :not_acceptable => 406,
32
+ :not_acceptable_anywhere => 606,
33
+ :not_acceptable_here => 488,
34
+ :not_found => 404,
35
+ :not_implemented => 501,
36
+ :ok => 200,
37
+ :payment_required => 402,
38
+ :precondition_failure => 580,
39
+ :provide_referer_identity => 429,
40
+ :proxy_authentication_required => 407,
41
+ :request_entity_too_large => 413,
42
+ :request_pending => 491,
43
+ :request_terminated => 487,
44
+ :request_timeout => 408,
45
+ :request_uri_too_long => 414,
46
+ :ringing => 180,
47
+ :security_agreement_required => 494,
48
+ :server_internal_error => 500,
49
+ :server_timeout => 504,
50
+ :service_unavailable => 503,
51
+ :session_interval_too_small => 422,
52
+ :session_progress => 183,
53
+ :temporarily_unavailable => 480,
54
+ :too_many_hops => 483,
55
+ :trying => 100,
56
+ :unauthorized => 401,
57
+ :undecipherable => 493,
58
+ :unsupported_certificate => 437,
59
+ :unsupported_media_type => 415,
60
+ :unsupported_uri_scheme => 416,
61
+ :use_identity_header => 428,
62
+ :use_proxy => 305,
63
+ :version_not_supported => 505,
64
+ }
65
+
66
+ class HeadersWrapper
67
+ def initialize(app, plural = false, address = false)
68
+ @app = app
69
+ method_definitions = <<-RUBY
70
+ def [](name)
71
+ @app.msg.get#{address ? "Address" : ""}Header#{plural ? "s" : ""}(name.to_s)#{plural ? ".to_a" : ""}
72
+ end
73
+ RUBY
74
+ if plural
75
+ method_definitions += <<-RUBY
76
+ def []=(name, values)
77
+ name = name.to_s
78
+ @app.msg.removeHeader(name)
79
+ if !values.nil?
80
+ values.each do |value|
81
+ @app.msg.add#{address ? "Address" : ""}Header(name, value#{address ? ", true" : ".to_s"})
82
+ end
83
+ end
84
+ end
85
+ RUBY
86
+ else
87
+ method_definitions += <<-RUBY
88
+ def []=(name, value)
89
+ if !value.nil?
90
+ @app.msg.set#{address ? "Address" : ""}Header(name.to_s, value)
91
+ else
92
+ @app.msg.removeHeader(name.to_s)
93
+ end
94
+ end
95
+ RUBY
96
+ end
97
+ class << self; self; end.class_eval method_definitions
98
+ end
99
+ end
100
+
101
+ module HelperMethods
102
+ def proxy(*args)
103
+ uri = args.shift
104
+ uri, options = nil, uri if uri.kind_of? Hash
105
+ options ||= args.shift || {}
106
+ if uri.nil?
107
+ uri = msg.requestURI
108
+ else
109
+ uri = sip_factory.createURI(uri)
110
+ end
111
+ proxy = msg.getProxy()
112
+ proxy.setRecordRoute(options[:record_route]) if options.has_key? :record_route
113
+ proxy.proxyTo(uri)
114
+ end
115
+
116
+ def header
117
+ @header_wrapper ||= HeadersWrapper::new(self)
118
+ end
119
+
120
+ def headers
121
+ @headers_wrapper ||= HeadersWrapper::new(self, true)
122
+ end
123
+
124
+ def address_header
125
+ @address_header_wrapper ||= HeadersWrapper::new(self, false, true)
126
+ end
127
+
128
+ def address_headers
129
+ @address_headers_wrapper ||= HeadersWrapper::new(self, true, true)
130
+ end
131
+
132
+ def add_header(name, value)
133
+ msg.addHeader(name.to_s, value)
134
+ end
135
+
136
+ def add_address_header(name, value, first = true)
137
+ msg.addAddressHeader(name.to_s, value, first)
138
+ end
139
+
140
+ def header?(name)
141
+ !msg.getHeader(name.to_s).nil?
142
+ end
143
+
144
+ def modify_header(header_name, pattern = nil, new_value = nil)
145
+ #FIXME: "JAVA" Code
146
+ if pattern
147
+ pattern = Regexp.new(/^#{pattern}$/) unless pattern.kind_of? Regexp
148
+ headers[header_name] = headers[header_name].map do |value|
149
+ value.gsub(pattern, new_value)
150
+ end
151
+ else
152
+ headers[header_name] = headers[header_name].map do |value|
153
+ yield value
154
+ end
155
+ end
156
+ end
157
+
158
+ def remove_header(name)
159
+ msg.removeHeader(name.to_s)
160
+ end
161
+
162
+ def send_response(status, *args)
163
+ create_args = [convert_status_code(status)]
164
+ create_args << args.shift unless args.empty? || args.first.kind_of?(Hash)
165
+ response = msg.createResponse(*create_args)
166
+ unless args.empty?
167
+ raise ArgumentError, "last argument should be a Hash" unless args.first.kind_of? Hash
168
+ args.first.each_pair do |name, value|
169
+ response.addHeader(name.to_s, value.to_s)
170
+ end
171
+ end
172
+ if block_given?
173
+ yield response
174
+ end
175
+ response.send
176
+ end
177
+
178
+ def create_address(addr, options = {})
179
+ addr = addr.to_s # TODO: Handle URI instances
180
+ address = sip_factory.createAddress(addr)
181
+ address.setExpires(options[:expires]) if options.has_key? :expires
182
+ address.setDisplayName(options[:display_name]) if options.has_key? :display_name
183
+
184
+ address
185
+ end
186
+
187
+ def push_route(route)
188
+ msg.pushRoute(sip_factory.createAddress(route))
189
+ end
190
+
191
+ private
192
+
193
+ def convert_status_code(symbol_or_int)
194
+ case symbol_or_int
195
+ when Integer: return symbol_or_int
196
+ when Symbol:
197
+ code = STATUS_CODES_MAP[symbol_or_int]
198
+ raise ArgumentError, "Unknown status code symbol: '#{symbol_or_int}'" unless code
199
+ code
200
+ else
201
+ raise ArgumentError, "Status code value should be a Symbol or Int not '#{symbol_or_int.class}'"
202
+ end
203
+ end
204
+ end
205
+ end
Binary file
Binary file
@@ -0,0 +1,13 @@
1
+ module SipatraJars
2
+ PATH = File.expand_path(File.dirname(__FILE__))
3
+
4
+ class << self
5
+ def all_jar_names
6
+ @all_jar_names ||= all_jar_paths.map { |path| File::basename(path) }
7
+ end
8
+
9
+ def all_jar_paths
10
+ @all_jar_paths ||= Dir[PATH + "/sipatra/*.jar"]
11
+ end
12
+ end
13
+ end
data/lib/sipatra.rb ADDED
@@ -0,0 +1,9 @@
1
+ if ENV['SIPATRA_PATH']
2
+ ENV['GEM_HOME'] = ENV['SIPATRA_PATH'] + '/../gems'
3
+ ENV['GEM_PATH'] = ENV['SIPATRA_PATH'] + '/../gems'
4
+ require 'rubygems'
5
+ end
6
+
7
+ require 'sipatra/base'
8
+
9
+ include Sipatra::Delegator
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sipatra
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 3
10
+ version: 0.0.3
11
+ platform: ruby
12
+ authors:
13
+ - Dominique Broeglin
14
+ - Jean-Baptiste Morin
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-11-30 00:00:00 +01:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: rspec
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 13
31
+ segments:
32
+ - 1
33
+ - 2
34
+ - 9
35
+ version: 1.2.9
36
+ type: :development
37
+ version_requirements: *id001
38
+ description: Sipatra is a Ruby DSL for easy writting of SIP Servlet applications
39
+ email:
40
+ - dominique.broeglin@gmail.com
41
+ - jean-baptiste.morin@nexcom.fr
42
+ executables: []
43
+
44
+ extensions: []
45
+
46
+ extra_rdoc_files: []
47
+
48
+ files:
49
+ - lib/sipatra-jars.rb
50
+ - lib/sipatra.rb
51
+ - lib/sipatra/base.rb
52
+ - lib/sipatra/commons-pool-1.5.5.jar
53
+ - lib/sipatra/extension_modules.rb
54
+ - lib/sipatra/helpers.rb
55
+ - lib/sipatra/sipatra-0.0.3-SNAPSHOT.jar
56
+ - lib/sipatra/slf4j-api-1.4.0.jar
57
+ - lib/sipatra/slf4j-log4j12-1.4.0.jar
58
+ has_rdoc: true
59
+ homepage: http://confluence.cipango.org/display/DOC/Sipatra
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --charset=UTF-8
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project:
88
+ rubygems_version: 1.3.7
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: DSL for easy writting of SIP Servlet applications
92
+ test_files: []
93
+