strelka 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/ChangeLog +156 -9
  4. data/History.rdoc +15 -0
  5. data/IDEAS.rdoc +17 -1
  6. data/MILESTONES.rdoc +1 -1
  7. data/Manifest.txt +10 -2
  8. data/Plugins.rdoc +4 -4
  9. data/README.rdoc +3 -3
  10. data/Rakefile +5 -4
  11. data/bin/strelka +19 -10
  12. data/contrib/hoetemplate/data/project/apps/file_name_app +1 -0
  13. data/contrib/hoetemplate/lib/file_name.rb.erb +3 -2
  14. data/examples/apps/hello-world +1 -0
  15. data/examples/apps/ws-chat +69 -0
  16. data/examples/apps/ws-echo +61 -0
  17. data/examples/gen-config.rb +6 -5
  18. data/lib/strelka/app/auth.rb +2 -2
  19. data/lib/strelka/app/errors.rb +1 -1
  20. data/lib/strelka/app/filters.rb +3 -2
  21. data/lib/strelka/app/negotiation.rb +2 -2
  22. data/lib/strelka/app/parameters.rb +1 -2
  23. data/lib/strelka/app/restresources.rb +3 -2
  24. data/lib/strelka/app/routing.rb +1 -1
  25. data/lib/strelka/app/sessions.rb +2 -2
  26. data/lib/strelka/app/templating.rb +7 -3
  27. data/lib/strelka/app.rb +5 -145
  28. data/lib/strelka/behavior/plugin.rb +4 -4
  29. data/lib/strelka/discovery.rb +211 -0
  30. data/lib/strelka/httprequest.rb +1 -0
  31. data/lib/strelka/httpresponse/negotiation.rb +7 -1
  32. data/lib/strelka/mixins.rb +4 -1
  33. data/lib/strelka/paramvalidator.rb +1 -1
  34. data/lib/strelka/plugins.rb +8 -6
  35. data/lib/strelka/websocketserver/routing.rb +116 -0
  36. data/lib/strelka/websocketserver.rb +147 -0
  37. data/lib/strelka.rb +5 -4
  38. data/spec/{lib/constants.rb → constants.rb} +3 -2
  39. data/spec/{lib/helpers.rb → helpers.rb} +15 -14
  40. data/spec/strelka/app/auth_spec.rb +145 -142
  41. data/spec/strelka/app/errors_spec.rb +20 -26
  42. data/spec/strelka/app/filters_spec.rb +67 -54
  43. data/spec/strelka/app/negotiation_spec.rb +8 -14
  44. data/spec/strelka/app/parameters_spec.rb +23 -29
  45. data/spec/strelka/app/restresources_spec.rb +98 -100
  46. data/spec/strelka/app/routing_spec.rb +57 -57
  47. data/spec/strelka/app/sessions_spec.rb +11 -17
  48. data/spec/strelka/app/templating_spec.rb +36 -40
  49. data/spec/strelka/app_spec.rb +48 -147
  50. data/spec/strelka/authprovider/basic_spec.rb +5 -11
  51. data/spec/strelka/authprovider/hostaccess_spec.rb +9 -15
  52. data/spec/strelka/authprovider_spec.rb +3 -9
  53. data/spec/strelka/cookie_spec.rb +32 -38
  54. data/spec/strelka/cookieset_spec.rb +31 -37
  55. data/spec/strelka/discovery_spec.rb +144 -0
  56. data/spec/strelka/exceptions_spec.rb +2 -8
  57. data/spec/strelka/httprequest/acceptparams_spec.rb +74 -83
  58. data/spec/strelka/httprequest/auth_spec.rb +5 -15
  59. data/spec/strelka/httprequest/negotiation_spec.rb +93 -103
  60. data/spec/strelka/httprequest/session_spec.rb +12 -22
  61. data/spec/strelka/httprequest_spec.rb +1 -7
  62. data/spec/strelka/httpresponse/negotiation_spec.rb +84 -76
  63. data/spec/strelka/httpresponse/session_spec.rb +25 -35
  64. data/spec/strelka/httpresponse_spec.rb +20 -26
  65. data/spec/strelka/mixins_spec.rb +66 -61
  66. data/spec/strelka/multipartparser_spec.rb +31 -37
  67. data/spec/strelka/paramvalidator_spec.rb +389 -373
  68. data/spec/strelka/plugins_spec.rb +17 -23
  69. data/spec/strelka/router/default_spec.rb +32 -38
  70. data/spec/strelka/router/exclusive_spec.rb +28 -34
  71. data/spec/strelka/router_spec.rb +2 -8
  72. data/spec/strelka/session/db_spec.rb +17 -15
  73. data/spec/strelka/session/default_spec.rb +22 -28
  74. data/spec/strelka/session_spec.rb +3 -9
  75. data/spec/strelka/websocketserver/routing_spec.rb +119 -0
  76. data/spec/strelka/websocketserver_spec.rb +149 -0
  77. data/spec/strelka_spec.rb +11 -13
  78. data.tar.gz.sig +3 -3
  79. metadata +22 -14
  80. metadata.gz.sig +0 -0
@@ -0,0 +1,116 @@
1
+ # -*- ruby -*-
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # encoding: utf-8
4
+
5
+ require 'strelka' unless defined?( Strelka )
6
+ require 'strelka/websocketserver' unless defined?( Strelka::WebSocketServer )
7
+ require 'strelka/plugin' unless defined?( Strelka::Plugin )
8
+
9
+ # Frame routing logic for Strelka WebSocketServers.
10
+ #
11
+ # For a protocol that defines its own opcodes:
12
+ #
13
+ # class ChatServer
14
+ # plugin :routing
15
+ #
16
+ # opcodes :nick => 7,
17
+ # :emote => 8
18
+ #
19
+ # on_text do |frame|
20
+ # # ...
21
+ # end
22
+ #
23
+ # on_nick do |frame|
24
+ # self.set_nick( frame.socket_id, frame.payload.read )
25
+ # end
26
+ #
27
+ #
28
+ module Strelka::WebSocketServer::Routing
29
+ extend Loggability,
30
+ Strelka::Plugin
31
+ include Strelka::Constants,
32
+ Mongrel2::WebSocket::Constants
33
+
34
+
35
+ # Loggability API -- set up logging under the 'strelka' log host
36
+ log_to :strelka
37
+
38
+ # Plugins API -- set up load order
39
+ # run_inside :templating, :filters, :parameters
40
+
41
+
42
+ # Class methods to add to classes with routing.
43
+ module ClassMethods # :nodoc:
44
+
45
+ # The list of routes to pass to the Router when the application is created
46
+ attr_reader :op_callbacks
47
+ @op_callbacks = {}
48
+
49
+ # The Hash of opcodes that can be hooked
50
+ attr_reader :opcode_map
51
+ @opcode_map = {}
52
+
53
+
54
+ ### Declare one or more opcodes in the form:
55
+ ###
56
+ ### {
57
+ ### <bit> => <label>,
58
+ ### }
59
+ def opcodes( hash )
60
+ @opcode_map ||= {}
61
+ @opcode_map.merge!( hash )
62
+ @opcode_map.each do |bit, label|
63
+ self.log.debug "Set opcode %p to %#0x" % [ label, bit ]
64
+ declarative = "on_#{label}"
65
+ block = self.make_declarative( label )
66
+ self.log.debug " declaring method %p on %p" % [ declarative, self ]
67
+ self.class.send( :define_method, declarative, &block )
68
+ end
69
+ end
70
+
71
+
72
+ ### Make a declarative method for setting the callback for frames with the specified
73
+ ### +opcode+ (Symbol).
74
+ def make_declarative( opcode )
75
+ self.log.debug "Making a declarative for %p" % [ opcode ]
76
+ return lambda do |&block|
77
+ self.log.debug "Setting handler for %p frames to %p" % [ opcode, block ]
78
+ methodname = "on_#{opcode}_frame"
79
+ define_method( methodname, &block )
80
+ self.op_callbacks[ opcode ] = self.instance_method( methodname )
81
+ end
82
+ end
83
+
84
+
85
+ ### Inheritance hook -- inheriting classes inherit their parents' routes table.
86
+ def inherited( subclass )
87
+ super
88
+ subclass.instance_variable_set( :@opcode_map, self.opcode_map.dup )
89
+ subclass.instance_variable_set( :@op_callbacks, self.op_callbacks.dup )
90
+ end
91
+
92
+
93
+ ### Extension callback -- install default opcode declaratives when the plugin
94
+ ### is registered.
95
+ def self::extended( mod )
96
+ super
97
+ mod.opcodes( Mongrel2::WebSocket::Constants::OPCODE_NAME )
98
+ end
99
+
100
+ end # module ClassMethods
101
+
102
+
103
+
104
+ ### Dispatch the incoming frame to its handler based on its opcode
105
+ def handle_frame( frame )
106
+ self.log.debug "[:routing] Opcode map is: %p" % [ self.class.opcode_map ]
107
+ opname = self.class.opcode_map[ frame.numeric_opcode ]
108
+ self.log.debug "[:routing] Routing frame: %p" % [ opname ]
109
+
110
+ handler = self.class.op_callbacks[ opname ] or return super
111
+
112
+ return handler.bind( self ).call( frame )
113
+ end
114
+
115
+ end # module Strelka::WebSocketServer::Routing
116
+
@@ -0,0 +1,147 @@
1
+ # -*- ruby -*-
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # encoding: utf-8
4
+
5
+ require 'mongrel2/handler'
6
+ require 'mongrel2/websocket'
7
+
8
+ require 'strelka' unless defined?( Strelka )
9
+ require 'strelka/mixins'
10
+ require 'strelka/plugins'
11
+ require 'strelka/discovery'
12
+
13
+
14
+ # WebSocket (RFC 6455) Server base class.
15
+ #
16
+ # class ChatServer < Strelka::WebSocketServer
17
+ #
18
+ # # Set up a Hash for participating users
19
+ # def initialize( * )
20
+ # super
21
+ # @users = {}
22
+ # end
23
+ #
24
+ # # Disconnect clients that don't answer a ping
25
+ # plugin :heartbeat
26
+ # heartbeat_rate 5.0
27
+ # idle_timeout 15.0
28
+ #
29
+ # # When a websocket is set up, add a new user to the table, but without a nick.
30
+ # on_handshake do |frame|
31
+ # @users[ frame.socket_id ] = nil
32
+ # return frame.response # accept the connection
33
+ # end
34
+ #
35
+ # # Handle incoming commands, which should be text frames
36
+ # on_text do |frame|
37
+ # senderid = frame.socket_id
38
+ # data = frame.payload.read
39
+ #
40
+ # # If the input starts with '/', it's a command (e.g., /quit, /nick, etc.)
41
+ # output = nil
42
+ # if data.start_with?( '/' )
43
+ # output = self.command( senderid, data[1..-1] )
44
+ # else
45
+ # output = self.say( senderid, data )
46
+ # end
47
+ #
48
+ # response = frame.response
49
+ # response.puts( output )
50
+ # return response
51
+ # end
52
+ #
53
+ # end # class ChatServer
54
+ #
55
+ class Strelka::WebSocketServer < Mongrel2::Handler
56
+ extend Strelka::MethodUtilities,
57
+ Strelka::PluginLoader,
58
+ Strelka::Discovery
59
+
60
+
61
+ # Loggability API -- log to the Strelka logger
62
+ log_to :strelka
63
+
64
+
65
+ ### Handle a WebSocket frame in +request+. If not overridden, WebSocket connections are
66
+ ### closed with a policy error status.
67
+ def handle_websocket( frame )
68
+ response = nil
69
+
70
+ # Dispatch the frame
71
+ response = catch( :close_websocket ) do
72
+ self.log.debug "Incoming WEBSOCKET frame (%p):%s" % [ frame, frame.headers.path ]
73
+ self.handle_frame( frame )
74
+ end
75
+
76
+ return response
77
+ end
78
+
79
+
80
+ ### Handle a WebSocket handshake HTTP +request+.
81
+ def handle_websocket_handshake( handshake )
82
+ self.log.warn "Incoming WEBSOCKET_HANDSHAKE request (%p)" % [ request.headers.path ]
83
+ return handshake.response( handshake.protocols.first )
84
+ end
85
+
86
+
87
+ ### Handle a disconnect notice from Mongrel2 via the given +request+. Its return value
88
+ ### is ignored.
89
+ def handle_disconnect( request )
90
+ self.log.info "Unhandled disconnect notice."
91
+ return nil
92
+ end
93
+
94
+
95
+ #########
96
+ protected
97
+ #########
98
+
99
+ ### Default frame handler.
100
+ def handle_frame( frame )
101
+ if frame.control?
102
+ self.handle_control_frame( frame )
103
+ else
104
+ self.handle_content_frame( frame )
105
+ end
106
+ end
107
+
108
+
109
+ ### Throw a :close_websocket frame that will close the current connection.
110
+ def close_with( frame, reason )
111
+ self.log.debug "Closing the connection: %p" % [ reason ]
112
+
113
+ # Make a CLOSE frame
114
+ frame = frame.response( :close )
115
+ frame.set_status( reason )
116
+
117
+ throw :close_websocket, frame
118
+ end
119
+
120
+
121
+ ### Handle an incoming control frame.
122
+ def handle_control_frame( frame )
123
+ self.log.debug "Handling control frame: %p" % [ frame ]
124
+
125
+ case frame.opcode
126
+ when :ping
127
+ return frame.response
128
+ when :pong
129
+ return nil
130
+ when :close
131
+ self.conn.reply_close( frame )
132
+ return nil
133
+ else
134
+ self.close_with( frame, CLOSE_BAD_DATA_TYPE )
135
+ end
136
+ end
137
+
138
+
139
+ ### Handle an incoming content frame.
140
+ def handle_content_frame( frame )
141
+ self.log.warn "Unhandled frame type %p" % [ frame.opcode ]
142
+ self.close_with( frame, CLOSE_BAD_DATA_TYPE )
143
+ end
144
+
145
+
146
+ end # class Strelka::WebSocketServer
147
+
data/lib/strelka.rb CHANGED
@@ -24,10 +24,10 @@ module Strelka
24
24
  log_as :strelka
25
25
 
26
26
  # Library version constant
27
- VERSION = '0.6.0'
27
+ VERSION = '0.7.0'
28
28
 
29
29
  # Version-control revision constant
30
- REVISION = %q$Revision: a043d61c759c $
30
+ REVISION = %q$Revision: 2caa91898658 $
31
31
 
32
32
  require 'strelka/constants'
33
33
  require 'strelka/exceptions'
@@ -36,6 +36,7 @@ module Strelka
36
36
  require 'strelka/app'
37
37
  require 'strelka/httprequest'
38
38
  require 'strelka/httpresponse'
39
+ require 'strelka/discovery'
39
40
 
40
41
 
41
42
  ### Get the library version. If +include_buildnum+ is true, the version string will
@@ -67,10 +68,10 @@ module Strelka
67
68
  ### named +gemname+. Returns the first matching class, or raises an exception if no
68
69
  ### app class was found.
69
70
  def self::App( appname, gemname=nil )
70
- path, _ = Strelka::App.find( appname, gemname )
71
+ path, _ = Strelka::Discovery.find( appname, gemname )
71
72
  raise LoadError, "Can't find the %s app." % [ appname ] unless path
72
73
 
73
- apps = Strelka::App.load( path ) or
74
+ apps = Strelka::Discovery.load( path ) or
74
75
  raise ScriptError "Loading %s didn't define a Strelka::App class." % [ path ]
75
76
 
76
77
  return apps.first
@@ -8,7 +8,8 @@ require 'strelka' unless defined?( Strelka )
8
8
  ### A collection of constants used in testing
9
9
  module Strelka::TestConstants # :nodoc:all
10
10
 
11
- include Strelka::Constants
11
+ include Strelka::Constants,
12
+ Mongrel2::WebSocket::Constants
12
13
 
13
14
  unless defined?( TEST_HOST )
14
15
 
@@ -24,7 +25,7 @@ module Strelka::TestConstants # :nodoc:all
24
25
 
25
26
  # Freeze all testing constants
26
27
  constants.each do |cname|
27
- const_get(cname).freeze
28
+ const_get(cname).freeze if cname.to_s.start_with?( 'TEST_' )
28
29
  end
29
30
  end
30
31
 
@@ -8,11 +8,8 @@ BEGIN {
8
8
  srcdir = basedir.parent
9
9
  mongrel2dir = srcdir + 'Mongrel2/lib'
10
10
 
11
- libdir = basedir + "lib"
12
-
13
- $LOAD_PATH.unshift( mongrel2dir.to_s ) unless $LOAD_PATH.include?( mongrel2dir.to_s )
14
- $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
15
- $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
11
+ $LOAD_PATH.unshift( mongrel2dir.to_s ) unless
12
+ !mongrel2dir.directory? || $LOAD_PATH.include?( mongrel2dir.to_s )
16
13
  }
17
14
 
18
15
  # SimpleCov test coverage reporting; enable this using the :coverage rake task
@@ -40,7 +37,7 @@ require 'mongrel2/testing'
40
37
  require 'strelka'
41
38
  require 'strelka/testing'
42
39
 
43
- require 'spec/lib/constants'
40
+ require_relative 'constants'
44
41
 
45
42
  Loggability.format_with( :color ) if $stdout.tty?
46
43
 
@@ -103,19 +100,23 @@ module Strelka::SpecHelpers
103
100
  end
104
101
 
105
102
 
106
- abort "You need a version of RSpec >= 2.6.0" unless defined?( RSpec )
107
-
108
103
  ### Mock with RSpec
109
- RSpec.configure do |c|
104
+ RSpec.configure do |config|
110
105
  include Strelka::TestConstants
111
106
 
112
- c.mock_with( :rspec )
107
+ config.treat_symbols_as_metadata_keys_with_true_values = true
108
+ config.run_all_when_everything_filtered = true
109
+ config.filter_run :focus
110
+ config.order = 'random'
111
+ config.mock_with( :rspec ) do |mock|
112
+ mock.syntax = :expect
113
+ end
113
114
 
114
- c.extend( Strelka::TestConstants )
115
+ config.extend( Strelka::TestConstants )
115
116
 
116
- c.include( Loggability::SpecHelpers )
117
- c.include( Mongrel2::SpecHelpers )
118
- c.include( Strelka::SpecHelpers )
117
+ config.include( Loggability::SpecHelpers )
118
+ config.include( Mongrel2::SpecHelpers )
119
+ config.include( Strelka::SpecHelpers )
119
120
  end
120
121
 
121
122
  # vim: set nosta noet ts=4 sw=4: