sipatra 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+