strelka 0.6.0 → 0.7.0

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.
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: