rest-firebase 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e5623f3812406296167b73e1b26510a060043d0b
4
- data.tar.gz: 45ddc73ba69941f7d74cdb183b8af4d6784f59f0
3
+ metadata.gz: 38ac75dc25a2212b5493f30523502a0c524e5423
4
+ data.tar.gz: 194f4cafa79ce00c6d33dd9dbdf086ce0c30bda3
5
5
  SHA512:
6
- metadata.gz: ffac8d5aabfb1468a32a7410a495ca0cb4dc0f8b9055c8b498dc5b209d2bc2e5a33027b45b65a7bd6c3f400fc9c9086036d1f727cbf06dc4b458f53e13d7c8e3
7
- data.tar.gz: 11e4cf1a5b78c289e8ce5af68a47c90f19877c7fc9b04a566d28fe87e78e0a26068fcf54b38c35d3c128ad9c940d72ae824805fa1ad845afd148adc2b98407a3
6
+ metadata.gz: 9e9dfc59ecf61bcdd560d72bfe851464f3a183bc514a98b1c5464d58f013cac9d2de2404be278005ed33f821f5becfd4a38984187fbfa83de96d95619ed04a53
7
+ data.tar.gz: 502858f091acd477c0e6ad2ed4c142845899ddaa8b16686ef2df5ff4e2134966bf7a54d3fd8c3e43b16a7f7bbfbc6c039a57d18d39ec66e235e01634195ab9e2
data/CHANGES.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGES
2
2
 
3
+ ## rest-firebase 0.9.1 -- 2014-06-28
4
+
5
+ * Now it would properly send JSON payload and headers.
6
+
3
7
  ## rest-firebase 0.9.0 -- 2014-05-13
4
8
 
5
9
  * Birthday!
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ $LOAD_PATH.unshift(File.expand_path("#{dir}/rest-core/lib"))
10
10
 
11
11
  Gemgem.init(dir) do |s|
12
12
  s.name = 'rest-firebase'
13
- s.version = '0.9.0'
13
+ s.version = '0.9.1'
14
14
  s.homepage = 'https://github.com/CodementorIO/rest-firebase'
15
15
 
16
16
  s.authors = ['Codementor', 'Lin Jen-Shin (godfat)']
data/doc/intro.md ADDED
@@ -0,0 +1,150 @@
1
+
2
+ # Codementor introduces you a new Firebase client for Ruby
3
+
4
+ ## Why we pick Firebase
5
+
6
+ Here at Codementor we implemented all the realtime facilities with
7
+ [Firebase][], which is a great tool and service for realtime communication,
8
+ especially for their JavaScript library which could handle all those edge
9
+ cases like whenever the clients disconnected unexpectedly, how we could
10
+ process the data offline and when we have a chance to reconnect, reconnect
11
+ and resend the offline data, etc, which are definitely common enough and we
12
+ shall not ignore them.
13
+
14
+ [Firebase]: https://www.firebase.com/
15
+
16
+ ## Why we need a Firebase client for Ruby
17
+
18
+ However, our server is written in Ruby, and we definitely need someway to let
19
+ the server communicate with the clients (browsers). For example, whenever
20
+ we want to programmatically broadcast some messages to certain users, it
21
+ would be much easier to do this from the server. Picking a Firebase client
22
+ for Ruby would be the most straightforward choice.
23
+
24
+ ## Existing Firebase client for Ruby did not fit our need
25
+
26
+ Unfortunately, eventually we realized that the existing Firebase client for
27
+ Ruby, namely [firebase-ruby][], did not fit our need. The main reason is that
28
+ it did not support the [streaming feature from Firebase][streaming], which is
29
+ extremely important whenever we want the clients periodically notify the
30
+ server, (e.g. online presence) since the server needs to know the status in
31
+ order to do some other stuffs underneath in realtime. We could probably
32
+ implement this on our server, but why not just use Firebase whenever it's
33
+ already implemented, and we're using it?
34
+
35
+ [firebase-ruby]: https://github.com/oscardelben/firebase-ruby
36
+ [streaming]: https://www.firebase.com/docs/rest-api.html#streaming-from-the-rest-api
37
+
38
+ ## [rest-firebase][]
39
+
40
+ Therefore we implemented our own Firebase client for Ruby, that is
41
+ [rest-firebase][]. It was built on top of [rest-core][], thus it has all
42
+ the advantages from rest-core, just like firebase-ruby was built on top
43
+ of [typhoeus][]. The highlights for rest-firebase are:
44
+
45
+ * Concurrent/asynchronous requests
46
+ * Streaming requests
47
+ * Generate Firebase JWT for you (auto-refresh is WIP)
48
+
49
+ [rest-firebase]: https://github.com/CodementorIO/rest-firebase
50
+ [rest-core]: https://github.com/godfat/rest-core
51
+ [typhoeus]: https://github.com/typhoeus/typhoeus
52
+
53
+ ### Concurrent/asynchronous requests
54
+
55
+ At times we want to notify two users at the same time, instead of preparing
56
+ two requests and wait for two requests to be done, we could simply do this:
57
+ (not a working example, just try to demonstrate, see [README.md][] for
58
+ working example)
59
+
60
+ ``` ruby
61
+ f = RestFirebase.new
62
+ f.put("users/#{a.id}", :message => 'Hi')
63
+ f.put("users/#{b.id}", :message => 'Oh')
64
+ ```
65
+
66
+ All requests are non-blocking, and it would only block when we try to look at
67
+ the response. Therefore the above requests would be processed concurrently and
68
+ asynchronously. To learn more about this, check [Concurrent HTTP Requests][].
69
+
70
+ Also, consequently, if you're not waiting for the requests to be done
71
+ somewhere, you might want to wait `at_exit` to make sure all
72
+ requests are properly done like this:
73
+
74
+ ``` ruby
75
+ at_exit do
76
+ RestFirebase.shutdown
77
+ end
78
+ ```
79
+
80
+ Which would also shutdown the [thread pool][] if you're using it.
81
+
82
+ [README.md]: https://github.com/CodementorIO/rest-firebase/blob/master/README.md
83
+ [Concurrent HTTP Requests]: https://github.com/CodementorIO/rest-firebase/blob/master/README.md#concurrent-http-requests
84
+ [thread pool]: https://github.com/godfat/rest-core#thread-pool--connection-pool
85
+
86
+ ### Streaming requests
87
+
88
+ To receive the online presence events, we have a specialized daemon to listen
89
+ on the presence node from Firebase. Something like below:
90
+
91
+ ``` ruby
92
+ es = RestFirebase.new.event_source('presence')
93
+ es.onerror do |error|
94
+ Codementor.handle_error(error) unless error.kind_of?(EOFError)
95
+ end
96
+
97
+ es.onreconnect do
98
+ firebase.auth = nil # refresh auth
99
+ !!@start # don't reconnect if we're closing
100
+ end
101
+
102
+ es.onmessage do |event, data|
103
+ next unless event == 'put'
104
+ next unless username = data['path'][%r{^/(\w+)/web$}, 1]
105
+ onpresence(username, data['data'])
106
+ end
107
+
108
+ es.start
109
+ sleep(1) while @start
110
+
111
+ es.close
112
+ ```
113
+
114
+ `onpresence` is the one doing our business logic.
115
+
116
+ ### Generate Firebase JWT for you (auto-refresh is WIP)
117
+
118
+ We could use Firebase JWT instead of our secret in order to make authorized
119
+ requests. This would be much secure than simply use the secret, which would
120
+ never expire unless we explicitly ask for. Checkout
121
+ [Authenticating Your Server][] for more detail. [rest-firebase][] could
122
+ generate one for you automatically by passing your secret to it like this:
123
+
124
+ ``` ruby
125
+ f = RestFirebase.new :secret => 'secret',
126
+ :d => {:auth_data => 'something'}
127
+ f.get('presence') # => attach JWT for auth in the request automatically
128
+ f.auth # => the JWT
129
+ f.auth = nil # => remove old JWT
130
+ f.auth # => generate a fresh new JWT
131
+ ```
132
+
133
+ Read the above document for what `:d` means here. Note that this JWT
134
+ would expire after 24 hours. Every time you initialize a new `RestFirebase`
135
+ it would generate a fresh new JWT, but if you want to keep using the same
136
+ instance, you would probably need to refresh the JWT by yourselves, just like
137
+ what we did when we tried to reconnect it in the streaming example.
138
+
139
+ [Authenticating Your Server]: https://www.firebase.com/docs/security/custom-login.html#authenticating-your-server
140
+
141
+ ## Summary
142
+
143
+ In order to take the full advantage of using Firebase with Ruby, we introduce
144
+ you [rest-firebase][], which highlights:
145
+
146
+ * Concurrent/asynchronous requests
147
+ * Streaming requests
148
+ * Generate Firebase JWT for you (auto-refresh is WIP)
149
+
150
+ Please feel free to try it and use it. It's released under Apache License 2.0.
data/lib/rest-firebase.rb CHANGED
@@ -7,7 +7,8 @@ RestFirebase = RC::Builder.client(:d, :secret, :auth) do
7
7
  use RC::Timeout , 10
8
8
 
9
9
  use RC::DefaultSite , 'https://SampleChat.firebaseIO-demo.com/'
10
- use RC::DefaultHeaders, {'Accept' => 'application/json'}
10
+ use RC::DefaultHeaders, {'Accept' => 'application/json',
11
+ 'Content-Type' => 'application/json'}
11
12
  use RC::DefaultQuery , nil
12
13
 
13
14
  use RC::FollowRedirect, 1
@@ -74,9 +75,14 @@ module RestFirebase::Client
74
75
  end
75
76
 
76
77
  def request env, app=app
77
- super(env.merge(REQUEST_PATH => "#{env[REQUEST_PATH]}.json",
78
- REQUEST_PAYLOAD => Json.encode(env[REQUEST_PAYLOAD])),
79
- app)
78
+ path = "#{env[REQUEST_PATH]}.json"
79
+ payload = if env[REQUEST_PAYLOAD]
80
+ {REQUEST_PAYLOAD => Json.encode(env[REQUEST_PAYLOAD])}
81
+ else
82
+ {}
83
+ end
84
+
85
+ super(env.merge(REQUEST_PATH => path).merge(payload), app)
80
86
  end
81
87
 
82
88
  def generate_auth opts={}
@@ -1,16 +1,16 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rest-firebase 0.9.0 ruby lib
2
+ # stub: rest-firebase 0.9.1 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "rest-firebase"
6
- s.version = "0.9.0"
6
+ s.version = "0.9.1"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib"]
10
10
  s.authors = [
11
11
  "Codementor",
12
12
  "Lin Jen-Shin (godfat)"]
13
- s.date = "2014-05-13"
13
+ s.date = "2014-06-28"
14
14
  s.description = "Ruby Firebase REST API client built on top of [rest-core][].\n\n[rest-core]: https://github.com/godfat/rest-core"
15
15
  s.email = ["help@codementor.io"]
16
16
  s.files = [
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
23
23
  "README.md",
24
24
  "Rakefile",
25
25
  "TODO.md",
26
+ "doc/intro.md",
26
27
  "lib/rest-firebase.rb",
27
28
  "rest-firebase.gemspec",
28
29
  "task/README.md",
data/test/test_api.rb CHANGED
@@ -14,6 +14,9 @@ describe RestFirebase do
14
14
 
15
15
  path = 'https://a.json?auth=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9%0A.eyJ2IjowLCJpYXQiOjAsImQiOm51bGx9%0A.C9JtzZhiCrsClNdAQcE7Irngr2BZJCH4x1p-IHxfrAo%3D%0A'
16
16
 
17
+ json = '{"status":"ok"}'
18
+ rbon = {'status' => 'ok'}
19
+
17
20
  def firebase
18
21
  RestFirebase.new(:secret => 'nnf')
19
22
  end
@@ -24,12 +27,15 @@ describe RestFirebase do
24
27
  end
25
28
 
26
29
  should 'put {"status":"ok"}' do
27
- json = '{"status":"ok"}'
28
- rbon = {'status' => 'ok'}
29
30
  stub_request(:put, path).with(:body => json).to_return(:body => json)
30
31
  firebase.put('https://a', rbon).should.eq rbon
31
32
  end
32
33
 
34
+ should 'have no payload for delete' do
35
+ stub_request(:delete, path).with(:body => nil).to_return(:body => json)
36
+ firebase.delete('https://a').should.eq rbon
37
+ end
38
+
33
39
  should 'parse event source' do
34
40
  stub_request(:get, path).to_return(:body => <<-SSE)
35
41
  event: put
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest-firebase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Codementor
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-13 00:00:00.000000000 Z
12
+ date: 2014-06-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-core
@@ -44,6 +44,7 @@ files:
44
44
  - README.md
45
45
  - Rakefile
46
46
  - TODO.md
47
+ - doc/intro.md
47
48
  - lib/rest-firebase.rb
48
49
  - rest-firebase.gemspec
49
50
  - task/README.md