rasti-web 0.0.3 → 0.0.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2b2ed7458b25215ed07dd7355f1a9dc43ce98d16
4
- data.tar.gz: df11d78ed700d06e98a565ac6671f90aeb8208ed
3
+ metadata.gz: fc7120ef16d98aaab088dc1d70dc5605cefce9bf
4
+ data.tar.gz: eba0f9c11f7df1078c299e10c108b83885eff925
5
5
  SHA512:
6
- metadata.gz: 30e33136ea36d5edcd6d2179fd08c03368e218bf42fba6001d18b579fa7b7ffcbb9a40a823a12cba311994232a4472156d62cb738716438e5d48b664121aa9b6
7
- data.tar.gz: 063a8972aa3439a801ade3ff9843f4e247622528d36a8fb477737a73e655e4b5f7f58acd817b4a63230e94501e5c76b5182e1f584e46348e91662ae3f570e9a2
6
+ metadata.gz: e0858476701c4d950f8827374183bed0cb69bbc341cf9755b5b0282a480770bcb8a6c4a81105ae5b4f435b9035a4d8ac53f01181fa2a237243b8a12e0cdeb390
7
+ data.tar.gz: 03ea9bd24694ad5fa7e38b892d84d52e3b24bf32702133fbcef4414812eeafad52228cc8430ba77508b3fc82bdbb29b4f68c79e7e3ebd4913ac6bf0c84bddbf1
data/.travis.yml CHANGED
@@ -3,4 +3,5 @@ rvm:
3
3
  - 1.9.3
4
4
  - 2.0
5
5
  - 2.1
6
+ - 2.2
6
7
  - jruby
@@ -0,0 +1,35 @@
1
+ module Rasti
2
+ module Web
3
+ class Channel
4
+
5
+ def initialize
6
+ @mutex = Mutex.new
7
+ @streams = []
8
+ end
9
+
10
+ def subscribe
11
+ Stream.new.tap do |stream|
12
+ @mutex.synchronize do
13
+ @streams << stream
14
+ end
15
+ end
16
+ end
17
+
18
+ def publish(message)
19
+ @mutex.synchronize do
20
+ @streams.delete_if(&:closed?)
21
+ Rasti::Web.logger.debug(Channel) { "Broadcasting (#{@streams.count} connections) -> #{message}" } unless @streams.empty?
22
+ @streams.each do |stream|
23
+ stream.write message
24
+ end
25
+ end
26
+ end
27
+
28
+ def self.[](id)
29
+ @channels ||= Hash.new { |h,k| h[k] = Channel.new }
30
+ @channels[id]
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -40,6 +40,12 @@ module Rasti
40
40
  script
41
41
  end
42
42
 
43
+ def css(stylesheet, *args)
44
+ respond_with extract_status(args),
45
+ extract_headers(args).merge('Content-Type' => 'text/css; charset=utf-8'),
46
+ stylesheet
47
+ end
48
+
43
49
  def file(filename, *args)
44
50
  content_type = MIME::Types.of(filename).first.content_type
45
51
  body = File.read filename
@@ -66,6 +72,14 @@ module Rasti
66
72
  layout(layout_template) { view_context.render template, locals }
67
73
  end
68
74
 
75
+ def server_sent_events(channel_id)
76
+ response.status = 200
77
+ response['Content-Type'] = 'text/event-stream'
78
+ response['Cache-Control'] = 'no-cache'
79
+ response['Connection'] = 'keep-alive'
80
+ response.body = Channel[channel_id].subscribe
81
+ end
82
+
69
83
  private
70
84
 
71
85
  def respond_with(status, headers, body)
@@ -0,0 +1,31 @@
1
+ module Rasti
2
+ module Web
3
+ class ServerSentEvent < String
4
+
5
+ attr_reader :data, :id, :event
6
+
7
+ private
8
+
9
+ def initialize(data, options={})
10
+ @data = data
11
+ @id = options[:id]
12
+ @event = options[:event]
13
+
14
+ super serialize
15
+ end
16
+
17
+ def serialize
18
+ serialized_data = data.respond_to?(:to_json) ? data.to_json : data.to_s
19
+
20
+ message = ''
21
+ message << "id: #{id}\n" if id
22
+ message << "event: #{event}\n" if event
23
+ serialized_data.split("\n").each do |d|
24
+ message << "data: #{d}\n"
25
+ end
26
+ message << "\n"
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ module Rasti
2
+ module Web
3
+ class Stream
4
+
5
+ TIMEOUT = 0.0001
6
+
7
+ def initialize
8
+ @queue = Queue.new
9
+ @closed = false
10
+ end
11
+
12
+ def write(message)
13
+ raise 'Closed stream' if closed?
14
+ @queue << message
15
+ end
16
+
17
+ def each
18
+ while opened?
19
+ message = @queue.pop
20
+ yield message if message
21
+ sleep TIMEOUT
22
+ end
23
+ end
24
+
25
+ def close
26
+ @closed = true
27
+ end
28
+
29
+ def closed?
30
+ @closed
31
+ end
32
+
33
+ def opened?
34
+ !closed?
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -1,5 +1,5 @@
1
1
  module Rasti
2
2
  module Web
3
- VERSION = '0.0.3'
3
+ VERSION = '0.0.4'
4
4
  end
5
5
  end
data/lib/rasti/web.rb CHANGED
@@ -4,6 +4,7 @@ require 'json'
4
4
  require 'mime-types'
5
5
  require 'class_config'
6
6
  require 'forwardable'
7
+ require 'logger'
7
8
 
8
9
  require_relative 'web/route'
9
10
  require_relative 'web/router'
@@ -14,6 +15,9 @@ require_relative 'web/view_context'
14
15
  require_relative 'web/render'
15
16
  require_relative 'web/request'
16
17
  require_relative 'web/controller'
18
+ require_relative 'web/channel'
19
+ require_relative 'web/stream'
20
+ require_relative 'web/server_sent_event'
17
21
  require_relative 'web/version'
18
22
 
19
23
  module Rasti
@@ -26,6 +30,7 @@ module Rasti
26
30
  attr_config :template_engines, [:erb]
27
31
  attr_config :default_layout, 'layout'
28
32
  attr_config :helpers, []
33
+ attr_config :logger, Logger.new(STDOUT)
29
34
 
30
35
  after_config do |config|
31
36
  config.helpers.each { |h| ViewContext.send :include, h }
@@ -20,4 +20,5 @@ end
20
20
  Rasti::Web.configure do |config|
21
21
  config.views_path = File.expand_path '../views', __FILE__
22
22
  config.helpers << ContextMethodHelper
23
+ config.logger.level = Logger::ERROR
23
24
  end
data/spec/render_spec.rb CHANGED
@@ -204,6 +204,44 @@ describe Rasti::Web::Render do
204
204
 
205
205
  end
206
206
 
207
+ describe 'CSS' do
208
+
209
+ it 'Body' do
210
+ render.css 'body{margin:0}'
211
+
212
+ response.status.must_equal 200
213
+ response['Content-Type'].must_equal 'text/css; charset=utf-8'
214
+ response.body.must_equal ['body{margin:0}']
215
+ end
216
+
217
+ it 'Body and status' do
218
+ render.css 'body{margin:0}', 206
219
+
220
+ response.status.must_equal 206
221
+ response['Content-Type'].must_equal 'text/css; charset=utf-8'
222
+ response.body.must_equal ['body{margin:0}']
223
+ end
224
+
225
+ it 'Body and headers' do
226
+ render.css 'body{margin:0}', 'Content-Encoding' => 'gzip'
227
+
228
+ response.status.must_equal 200
229
+ response['Content-Type'].must_equal 'text/css; charset=utf-8'
230
+ response['Content-Encoding'].must_equal 'gzip'
231
+ response.body.must_equal ['body{margin:0}']
232
+ end
233
+
234
+ it 'Body, status and headers' do
235
+ render.css 'body{margin:0}', 206, 'Content-Encoding' => 'gzip'
236
+
237
+ response.status.must_equal 206
238
+ response['Content-Type'].must_equal 'text/css; charset=utf-8'
239
+ response['Content-Encoding'].must_equal 'gzip'
240
+ response.body.must_equal ['body{margin:0}']
241
+ end
242
+
243
+ end
244
+
207
245
  describe 'File' do
208
246
 
209
247
  let(:filename) { File.expand_path '../sample_file.zip', __FILE__ }
@@ -0,0 +1,29 @@
1
+ require 'minitest_helper'
2
+
3
+ describe 'Straming' do
4
+
5
+ let(:request) { Rack::Request.new Hash.new }
6
+ let(:response) { Rack::Response.new }
7
+ let(:render) { Rasti::Web::Render.new request, response }
8
+
9
+ it 'Server sent events' do
10
+ events = []
11
+ stream = render.server_sent_events :test_channel
12
+
13
+ thread = Thread.new do
14
+ stream.each { |e| events << e }
15
+ end
16
+
17
+ 3.times do |i|
18
+ data = {text: "Tick #{i}"}
19
+ event = Rasti::Web::ServerSentEvent.new data, id: i, event: 'tick'
20
+ Rasti::Web::Channel[:test_channel].publish event
21
+ end
22
+
23
+ while events.count < 3; sleep 0.0001 end
24
+ stream.close
25
+
26
+ events.must_equal 3.times.map { |i| "id: #{i}\nevent: tick\ndata: {\"text\":\"Tick #{i}\"}\n\n" }
27
+ end
28
+
29
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rasti-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Naiman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-03 00:00:00.000000000 Z
11
+ date: 2015-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -183,12 +183,15 @@ files:
183
183
  - lib/rasti-web.rb
184
184
  - lib/rasti/web.rb
185
185
  - lib/rasti/web/application.rb
186
+ - lib/rasti/web/channel.rb
186
187
  - lib/rasti/web/controller.rb
187
188
  - lib/rasti/web/endpoint.rb
188
189
  - lib/rasti/web/render.rb
189
190
  - lib/rasti/web/request.rb
190
191
  - lib/rasti/web/route.rb
191
192
  - lib/rasti/web/router.rb
193
+ - lib/rasti/web/server_sent_event.rb
194
+ - lib/rasti/web/stream.rb
192
195
  - lib/rasti/web/template.rb
193
196
  - lib/rasti/web/version.rb
194
197
  - lib/rasti/web/view_context.rb
@@ -203,6 +206,7 @@ files:
203
206
  - spec/route_spec.rb
204
207
  - spec/router_spec.rb
205
208
  - spec/sample_file.zip
209
+ - spec/streaming_spec.rb
206
210
  - spec/template_spec.rb
207
211
  - spec/views/context_and_locals.erb
208
212
  - spec/views/context_method.erb
@@ -230,7 +234,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
230
234
  version: '0'
231
235
  requirements: []
232
236
  rubyforge_project:
233
- rubygems_version: 2.2.2
237
+ rubygems_version: 2.4.7
234
238
  signing_key:
235
239
  specification_version: 4
236
240
  summary: Web blocks to build robust applications
@@ -245,6 +249,7 @@ test_files:
245
249
  - spec/route_spec.rb
246
250
  - spec/router_spec.rb
247
251
  - spec/sample_file.zip
252
+ - spec/streaming_spec.rb
248
253
  - spec/template_spec.rb
249
254
  - spec/views/context_and_locals.erb
250
255
  - spec/views/context_method.erb