tuppari 0.1.1

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.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
6
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'rest-client', '1.6.7'
4
+ gem 'json', '1.7.4'
5
+
6
+ gem 'debugger'
7
+ gem 'rspec'
8
+
data/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # Tuppari client for Ruby
2
+
3
+ ## About Tuppari
4
+
5
+ [Tuppari](http://hakobera.github.com/tuppari/) is an experimental implementation of unbreakable message broadcasting system using WebSocket and Amazon Web Services by [@hakobera](https://github.com/hakobera).
6
+
7
+ https://github.com/hakobera/tuppari
8
+
9
+ https://github.com/hakobera/tuppari-servers
10
+
11
+
12
+ ## Tuppari for Ruby developers
13
+
14
+ You can easily build a Tuppari application by just using Ruby API. Let's get started now!
15
+
16
+ ### Gemfile
17
+
18
+ Prepare Gemfile as follows.
19
+
20
+ ```ruby
21
+ source 'https://rubygems.org'
22
+
23
+ gem 'tuppari'
24
+ ```
25
+
26
+ ### Getting Started
27
+
28
+ And then invoke `bundle console` to try Tuppari.
29
+
30
+ ```ruby
31
+ require 'tuppari'
32
+
33
+ Tuppari.create_account(YOUR_ID, PASSWORD)
34
+
35
+ tuppari = Tuppari.login(YOUR_ID, PASSWORD)
36
+
37
+ application = tuppari.create_application('first-tuppari')
38
+
39
+ open('tuppari.html', 'w') do |f|
40
+ html = <<"EOF"
41
+ <html>
42
+ <head>
43
+ <script src="http://cdn.tuppari.com/0.1.0/tuppari.min.js"></script>
44
+ <script>
45
+ var client, channel;
46
+ client = tuppari.createClient({applicationId: '#{application.id}'});
47
+ channel = client.subscribe('ch');
48
+ channel.bind('update', function (msg) {
49
+ console.log(msg);
50
+ });
51
+ </script>
52
+ </head>
53
+ <body>Check JavaScript console.</body>
54
+ </html>
55
+ EOF
56
+ f.write(html)
57
+ end
58
+
59
+ #
60
+ # [notice] Please open this 'tuppari.html' file in browser.
61
+ #
62
+
63
+ tuppari.application = application # or tuppari.load_application_by_name('first-tuppari')
64
+
65
+ tuppari.publish_message(
66
+ :channel => 'ch',
67
+ :event => 'update',
68
+ :message => "Hello, Tuppari! (#{Time.now})"
69
+ )
70
+ ```
71
+
72
+ ### Publishing messages without account authentication
73
+
74
+ Tuppari account authentication is not needed for publishing messages. And following values for the target application are required.
75
+
76
+ - application_id
77
+ - access_key_id (for the application)
78
+ - access_secret_key (for the application)
79
+
80
+ ```ruby
81
+ application = Tuppari::Application.new(
82
+ :id => 'xxxx',
83
+ :access_key_id => 'yyy',
84
+ :access_secret_key => 'zzz'
85
+ ) # or application = tuppari.get_application('first-tuppari')
86
+
87
+ Tuppari.publish_message(
88
+ :application => application,
89
+ :channel => 'ch',
90
+ :event => 'update',
91
+ :message => "Hello, Tuppari! (#{Time.now})"
92
+ )
93
+ ```
94
+
data/lib/tuppari.rb ADDED
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'logger'
4
+ require 'json'
5
+ require 'rest_client'
6
+ require 'time'
7
+ require 'tuppari/auth'
8
+ require 'tuppari/application'
9
+ require 'tuppari/authentication_error'
10
+ require 'tuppari/client'
11
+ require 'tuppari/client_error'
12
+ require 'tuppari/server_url'
13
+
14
+ # Tuppari API client
15
+ #
16
+ # `Tuppari` is an experimental implementation of unbreakable message broadcasting system
17
+ # using WebSocket and Amazon Web Services.
18
+ #
19
+ # see also https://github.com/hakobera/tuppari-servers/wiki/API-Reference
20
+ #
21
+ module Tuppari
22
+
23
+ # Creates a new Tuppari::Client instance.
24
+ def self.new(params = {})
25
+ Tuppari::Client.new(params)
26
+ end
27
+
28
+ def self.create_account(account_name, password)
29
+ new().create_account(account_name, password)
30
+ end
31
+
32
+ def self.login(account_name, password)
33
+ new().login(account_name, password)
34
+ end
35
+
36
+ def self.publish_message(params)
37
+ Tuppari.new().publish_message(params)
38
+ end
39
+
40
+ end
41
+
@@ -0,0 +1,16 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Tuppari
4
+ class Application
5
+
6
+ attr_accessor :name, :id, :access_key_id, :access_secret_key
7
+
8
+ def initialize(params)
9
+ @name = params[:name]
10
+ @id = params[:id]
11
+ @access_key_id = params[:access_key_id]
12
+ @access_secret_key = params[:access_secret_key]
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,107 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'openssl'
4
+ require 'digest'
5
+ require 'json'
6
+
7
+ module Tuppari
8
+ module Auth
9
+
10
+ def self.create_canonical_uri(uri)
11
+ if %r{^http(s)*://}.match(uri)
12
+ uri.sub(%r{^http(s)*://[^/]+/}, '/')
13
+ elsif %r{^[^/]}.match(uri)
14
+ "/#{uri}"
15
+ else
16
+ uri
17
+ end
18
+ end
19
+
20
+ def self.create_canonical_query_string(query_string)
21
+ if query_string.nil?
22
+ ''
23
+ else
24
+ query_string.split("&").sort_by { |e| e.split("=").first }.join('&')
25
+ end
26
+ end
27
+
28
+ def self.create_canonical_headers(headers)
29
+ if headers.nil?
30
+ ''
31
+ else
32
+ downcase_keys(headers).to_a.sort_by { |k, v| k }.map { |k, v| "#{k}:#{v}" }.join("\n")
33
+ end
34
+ end
35
+
36
+ def self.create_signed_headers(headers)
37
+ if headers.nil?
38
+ ''
39
+ else
40
+ downcase_keys(headers).to_a.sort_by { |k, v| k }.map { |k, v| k }.join(';')
41
+ end
42
+ end
43
+
44
+ def self.create_body_hash(body_params)
45
+ sha256 = Digest::SHA256.new
46
+ digest = sha256.digest(JSON.unparse(body_params))
47
+ Digest.hexencode(digest)
48
+ end
49
+
50
+ def self.create_canonical_request(method, uri, query_string, headers, body_params)
51
+ request = []
52
+ request << method
53
+ request << create_canonical_uri(uri)
54
+ request << create_canonical_query_string(query_string)
55
+ request << create_canonical_headers(headers)
56
+ request << create_signed_headers(headers)
57
+ request << create_body_hash(body_params)
58
+ request.join("\n")
59
+ end
60
+
61
+ def self.create_string_to_sign(canonical_request, request_time)
62
+ result = []
63
+ result << "SHA256"
64
+ result << request_time.gmtime.strftime("%Y%m%dT%H%M%SZ")
65
+ sha256 = Digest::SHA256.new
66
+ digest = sha256.digest(canonical_request)
67
+ result << Digest.hexencode(digest)
68
+ result.join("\n")
69
+ end
70
+
71
+ def self.create_signature(secret, string_to_sign, request_time, host)
72
+ signing_key = create_hmac_hash_value(create_hmac_hash_value("TUPPARI#{secret}", request_time.gmtime.strftime("%Y%m%dT%H%M%SZ")), host)
73
+ create_hmac_hash_value(signing_key, string_to_sign)
74
+ end
75
+
76
+ def self.create_authorization_header(params)
77
+ id = params[:id]
78
+ secret = params[:secret]
79
+ method = params[:method] || 'POST'
80
+ uri = params[:uri]
81
+ host = params[:host] || 'api.tuppari.com'
82
+ query_string = params[:query_string] || ''
83
+ headers = params[:headers] || {}
84
+ body_params = params[:body_params] || {}
85
+ request_time = params[:request_time] || Time.now
86
+
87
+ signed_headers = create_signed_headers(headers)
88
+ canonical_request = create_canonical_request(method, uri, query_string, headers, body_params)
89
+ string_to_sign = create_string_to_sign(canonical_request, request_time)
90
+ signature = create_signature(secret, string_to_sign, request_time, host)
91
+ "HMAC-SHA256 Credential=#{id},SignedHeaders=#{signed_headers},Signature=#{signature}"
92
+ end
93
+
94
+ protected
95
+
96
+ def self.downcase_keys(headers)
97
+ headers.each_with_object({}) { |(k, v), hash|
98
+ hash[k.downcase] = v
99
+ }
100
+ end
101
+
102
+ def self.create_hmac_hash_value(key, data)
103
+ OpenSSL::HMAC.hexdigest('sha256', key, data)
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,6 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Tuppari
4
+ class AuthenticationError < Exception
5
+ end
6
+ end
@@ -0,0 +1,290 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'logger'
4
+ require 'time'
5
+ require 'json'
6
+ require 'rest_client'
7
+
8
+ require 'tuppari'
9
+
10
+ module Tuppari
11
+ class Client
12
+
13
+ attr_accessor :account_name, :account_secret, :application, :log
14
+
15
+ def initialize(params = {})
16
+ @log = Logger.new(params[:log_output] || STDOUT)
17
+ @log.level = params[:log_level] || Logger::INFO
18
+ @account_name = params[:account_name]
19
+ @account_secret = params[:account_secret]
20
+ setup_application(params)
21
+ end
22
+
23
+ def load_application_by_name(application_name)
24
+ setup_application({:application_name => application_name})
25
+ self
26
+ end
27
+
28
+ def create_account(account_name, password)
29
+ body = JSON.unparse({"accountName" => account_name, "password" => password})
30
+ begin
31
+ RestClient.post(Tuppari::ServerURL::ACCOUNTS_REGISTER, body, :content_type => :json)
32
+ rescue RestClient::Exception => e
33
+ @log.warn("Failed to create a new Tuppari account (#{e}, #{e.http_body})")
34
+ raise e
35
+ rescue Exception => e
36
+ @log.warn("Failed to create a new Tuppari account (#{e})")
37
+ raise e
38
+ end
39
+ end
40
+
41
+ def login(account_name, password)
42
+ body = JSON.unparse({:accountName => account_name, :password => password})
43
+ begin
44
+ body = RestClient.post(Tuppari::ServerURL::ACCOUNTS_AUTH, body, :content_type => :json)
45
+ credentials = JSON.parse(body)['credentials']
46
+ @account_name = credentials['id']
47
+ @account_secret = credentials['secret']
48
+ @log.debug {
49
+ "Authenticated tuppari user (account_name:#{@account_name}, account_secret:#{@account_secret})"
50
+ }
51
+ rescue RestClient::Exception => e
52
+ @log.warn("Failed to authenticate your Tuppari account (#{e}, #{e.http_body})")
53
+ raise e
54
+ rescue Exception => e
55
+ @log.warn("Failed to authenticate your Tuppari account (#{e})")
56
+ raise e
57
+ end
58
+ self
59
+ end
60
+
61
+ def is_authenticated?
62
+ !@account_name.nil? && !@account_secret.nil?
63
+ end
64
+
65
+ def create_application(application_name)
66
+ unless is_authenticated?
67
+ raise Tuppari::AuthenticationError.new("Call #authenticate(account_name, password) before.")
68
+ end
69
+
70
+ time = Time.now
71
+ headers = headers('CreateApplication', time)
72
+ body_params = {:applicationName => application_name.to_s}
73
+ auth_header = Tuppari::Auth.create_authorization_header(
74
+ :id => @account_name,
75
+ :secret => @account_secret,
76
+ :method => 'POST',
77
+ :uri => Tuppari::ServerURL::APPLICATIONS,
78
+ :host => 'api.tuppari.com',
79
+ :query_string => '',
80
+ :headers => headers,
81
+ :body_params => body_params,
82
+ :request_time => time
83
+ )
84
+ begin
85
+ body = RestClient.post(Tuppari::ServerURL::APPLICATIONS,
86
+ JSON.unparse(body_params),
87
+ headers.merge(:authorization => auth_header))
88
+ @log.debug {
89
+ "create_application response: #{body}"
90
+ }
91
+ @log.info {
92
+ "Tuppari application is created. (#{application_name})"
93
+ }
94
+ response = JSON.parse(body)
95
+ Tuppari::Application.new(
96
+ :name => response['applicationName'],
97
+ :id => response['applicationId'],
98
+ :access_key_id => response['accessKeyId'],
99
+ :access_secret_key => response['accessSecretKey']
100
+ )
101
+ rescue RestClient::Exception => e
102
+ @log.warn("Failed to create a new Tuppari application (#{e}, #{e.http_body})")
103
+ raise e
104
+ rescue Exception => e
105
+ @log.warn("Failed to create a new Tuppari application (#{e})")
106
+ raise e
107
+ end
108
+ end
109
+
110
+ def delete_application(application_name)
111
+ unless is_authenticated?
112
+ raise Tuppari::AuthenticationError.new("Call #authenticate(account_name, password) before.")
113
+ end
114
+
115
+ time = Time.now
116
+ headers = headers('DeleteApplication', time)
117
+ body_params = {:applicationName => application_name}
118
+ auth_header = Tuppari::Auth.create_authorization_header(
119
+ :id => @account_name,
120
+ :secret => @account_secret,
121
+ :method => 'POST',
122
+ :uri => Tuppari::ServerURL::APPLICATIONS,
123
+ :host => 'api.tuppari.com',
124
+ :query_string => '',
125
+ :headers => headers,
126
+ :body_params => body_params,
127
+ :request_time => time
128
+ )
129
+ begin
130
+ RestClient.post(Tuppari::ServerURL::APPLICATIONS,
131
+ JSON.unparse(body_params),
132
+ headers.merge(:authorization => auth_header))
133
+ @log.info {
134
+ "Tuppari application is deleted. (#{application_name})"
135
+ }
136
+ rescue RestClient::Exception => e
137
+ @log.warn("Failed to delete a Tuppari application (#{e}, #{e.http_body})")
138
+ raise e
139
+ rescue Exception => e
140
+ @log.warn("Failed to delete a Tuppari application (#{e})")
141
+ raise e
142
+ end
143
+ nil
144
+ end
145
+
146
+ def get_application(application_name)
147
+ get_application_list().find { |app| app.name == application_name }
148
+ end
149
+
150
+ def get_application_list()
151
+ unless is_authenticated?
152
+ raise Tuppari::AuthenticationError.new("Call #authenticate(account_name, password) before.")
153
+ end
154
+
155
+ time = Time.now
156
+ headers = headers('ListApplication', time)
157
+ body_params = {}
158
+ auth_header = Tuppari::Auth.create_authorization_header(
159
+ :id => @account_name,
160
+ :secret => @account_secret,
161
+ :method => 'POST',
162
+ :uri => Tuppari::ServerURL::APPLICATIONS,
163
+ :host => 'api.tuppari.com',
164
+ :query_string => '',
165
+ :headers => headers,
166
+ :body_params => body_params,
167
+ :request_time => time
168
+ )
169
+ begin
170
+ body = RestClient.post(Tuppari::ServerURL::APPLICATIONS,
171
+ JSON.unparse(body_params),
172
+ headers.merge(:authorization => auth_header))
173
+ @log.debug {
174
+ "get_application_list response: #{response}"
175
+ }
176
+ JSON.parse(body).to_a.map { |name, app|
177
+ Tuppari::Application.new(
178
+ :name => app['name'],
179
+ :id => app['applicationId'],
180
+ :access_key_id => app['accessKeyId'],
181
+ :access_secret_key => app['accessSecretKey']
182
+ )
183
+ }
184
+ rescue RestClient::Exception => e
185
+ @log.warn("Failed to get the Tuppari application list (#{e}, #{e.http_body})")
186
+ raise e
187
+ rescue Exception => e
188
+ @log.warn("Failed to get the Tuppari application list (#{e})")
189
+ raise e
190
+ end
191
+ end
192
+
193
+ def publish_message(params)
194
+
195
+ setup_application(params)
196
+ if @application.nil?
197
+ raise Tuppari::ClientError.new("Specify Tuppari application to publish messages.")
198
+ end
199
+
200
+ channel = params[:channel]
201
+ event = params[:event]
202
+ message = params[:message]
203
+
204
+ time = Time.now
205
+ headers = headers('PublishMessage', time)
206
+ body_params = {
207
+ :applicationId => @application.id,
208
+ :channel => channel,
209
+ :event => event,
210
+ :message => message
211
+ }
212
+ auth_header = Tuppari::Auth.create_authorization_header(
213
+ :id => @application.access_key_id,
214
+ :secret => @application.access_secret_key,
215
+ :method => 'POST',
216
+ :uri => Tuppari::ServerURL::MESSAGES,
217
+ :host => 'api.tuppari.com',
218
+ :query_string => '',
219
+ :headers => headers,
220
+ :body_params => body_params,
221
+ :request_time => time
222
+ )
223
+ begin
224
+ body = RestClient.post(Tuppari::ServerURL::MESSAGES,
225
+ JSON.unparse(body_params),
226
+ headers.merge(:authorization => auth_header))
227
+ @log.debug {
228
+ "Tuppari message has been sent. (#{@application.id},#{channel},#{event},#{message})"
229
+ }
230
+ JSON.parse(body)
231
+ rescue RestClient::Exception => e
232
+ @log.warn {
233
+ "Failed to publish a Tuppari message (#{e}, #{e.http_body}, application_id:#{@application.id}, " +
234
+ "channel:#{channel}, event:#{event}, message:#{message})"
235
+ }
236
+ raise e
237
+ rescue Exception => e
238
+ @log.warn {
239
+ "Failed to publish a Tuppari message (#{e}, application_id:#{@application.id}, " +
240
+ "channel:#{channel}, event:#{event}, message:#{message})"
241
+ }
242
+ raise e
243
+ end
244
+ end
245
+
246
+ def get_service_info()
247
+ begin
248
+ body = RestClient.get(Tuppari::ServerURL::INFO, 'Content-type' => 'application/json')
249
+ JSON.parse(body)
250
+ rescue RestClient::Exception => e
251
+ @log.warn("Failed to get the Tuppari service info (#{e}, #{e.http_body})")
252
+ raise e
253
+ rescue Exception => e
254
+ @log.warn("Failed to get the Tuppari service info (#{e})")
255
+ raise e
256
+ end
257
+ end
258
+
259
+ protected
260
+
261
+ def setup_application(params)
262
+ if !params[:application].nil?
263
+ app = params[:application]
264
+ if app.is_a? Tuppari::Application
265
+ @application = app
266
+ else
267
+ raise Tuppari::ClientError.new("application should be a Tuppari::Application object.")
268
+ end
269
+ elsif !params[:application_name].nil?
270
+ application_name = params[:application_name]
271
+ application = get_application_list().find { |app| app.name == application_name }
272
+ if application.nil?
273
+ raise Tuppari::ClientError.new("Application is not found (application_name: #{application_name})")
274
+ else
275
+ @application = application
276
+ end
277
+ end
278
+ end
279
+
280
+ def headers(operation, time)
281
+ {
282
+ 'Host' => 'api.tuppari.com',
283
+ 'Content-type' => 'application/json',
284
+ 'X-Tuppari-Date' => time.gmtime.rfc2822,
285
+ 'X-Tuppari-Operation' => operation
286
+ }
287
+ end
288
+
289
+ end
290
+ end
@@ -0,0 +1,6 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Tuppari
4
+ class ClientError < Exception
5
+ end
6
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Tuppari
4
+ module ServerURL
5
+
6
+ BASE_URL = 'https://api.tuppari.com'
7
+
8
+ ACCOUNTS_REGISTER = BASE_URL + '/accounts/register'
9
+
10
+ ACCOUNTS_AUTH = BASE_URL + '/accounts/auth'
11
+
12
+ APPLICATIONS = BASE_URL + '/applications'
13
+
14
+ MESSAGES = BASE_URL + '/messages'
15
+
16
+ INFO = BASE_URL + '/info'
17
+
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Tuppari
4
+ VERSION = "0.1.1"
5
+ end
6
+
data/spec/README.md ADDED
@@ -0,0 +1,6 @@
1
+ Before testing, update your `~/.bash_profile` as follows:
2
+
3
+ ```sh
4
+ export TUPPARI_ACCOUNT_NAME=YOUR_ACCOUNT
5
+ export TUPPARI_PASSWORD=YOUR_PASSWORd
6
+ ```
@@ -0,0 +1,128 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'tuppari'
4
+
5
+ describe Tuppari::Auth do
6
+
7
+ it "should have correct #create_canonical_uri" do
8
+ Tuppari::Auth.create_canonical_uri('foo/bar').should eq('/foo/bar')
9
+ Tuppari::Auth.create_canonical_uri('/foo/bar').should eq('/foo/bar')
10
+ Tuppari::Auth.create_canonical_uri('http://www.google.com/foo/bar').should eq('/foo/bar')
11
+ end
12
+
13
+ it "should have correct #create_canonical_query_string" do
14
+ Tuppari::Auth.create_canonical_query_string(nil).should eq('')
15
+ Tuppari::Auth.create_canonical_query_string('').should eq('')
16
+ Tuppari::Auth.create_canonical_query_string('a=b').should eq('a=b')
17
+ Tuppari::Auth.create_canonical_query_string('a=b&c=d').should eq('a=b&c=d')
18
+ Tuppari::Auth.create_canonical_query_string('c=d&a=b').should eq('a=b&c=d')
19
+ Tuppari::Auth.create_canonical_query_string('c=d&a=b&c=e').should eq('a=b&c=d&c=e')
20
+ end
21
+
22
+ it "should have correct #create_canonical_headers" do
23
+ Tuppari::Auth.create_canonical_headers(nil).should eq('')
24
+ Tuppari::Auth.create_canonical_headers({}).should eq('')
25
+
26
+ headers = {
27
+ 'X-Tuppari-Operation' => 'CreateApplication',
28
+ 'Content-type' => 'application/json',
29
+ 'Host' => 'api.tuppari.com'
30
+ }
31
+ Tuppari::Auth.create_canonical_headers(headers).should eq("content-type:application/json\nhost:api.tuppari.com\nx-tuppari-operation:CreateApplication")
32
+ end
33
+
34
+ it "should have correct #create_signed_headers" do
35
+ Tuppari::Auth.create_signed_headers(nil).should eq('')
36
+ Tuppari::Auth.create_signed_headers({}).should eq('')
37
+
38
+ headers = {
39
+ 'X-Tuppari-Operation' => 'CreateApplication',
40
+ 'Content-type' => 'application/json',
41
+ 'Host' => 'api.tuppari.com'
42
+ }
43
+ Tuppari::Auth.create_signed_headers(headers).should eq('content-type;host;x-tuppari-operation')
44
+ end
45
+
46
+ it 'should have correct #create_body_hash' do
47
+ Tuppari::Auth.create_body_hash({'a' => 'b', 'c' => 'd'}).should eq('b85c7da93e8790518898c280e15e3f1af5d46bf4aaa4407690f0f0a3b0316478')
48
+ end
49
+
50
+ it 'should have correct #create_canonical_request' do
51
+ headers = {
52
+ 'X-Tuppari-Operation' => 'CreateApplication',
53
+ 'Content-type' => 'application/json',
54
+ 'Host' => 'api.tuppari.com'
55
+ }
56
+ body_params = {'applicationName' => 'example1'}
57
+ request = Tuppari::Auth.create_canonical_request('POST', '/test', 'b=v2&a=v1', headers, body_params)
58
+
59
+ request.should eq("POST\n" +
60
+ "/test\n" +
61
+ "a=v1&b=v2\n" +
62
+ "content-type:application/json\n" +
63
+ "host:api.tuppari.com\n" +
64
+ "x-tuppari-operation:CreateApplication\n" +
65
+ "content-type;host;x-tuppari-operation\n" +
66
+ "8f2d5fe4a93000d3546e578d265fc936806f6ef6dc6f7ee87715e1a5c514c168")
67
+ end
68
+
69
+ it 'should have correct #create_string_to_sign' do
70
+ request = "POST\n" +
71
+ "/test\n" +
72
+ "a=v1&b=v2\n" +
73
+ "content-type:application/json\n" +
74
+ "host:api.tuppari.com\n" +
75
+ "x-tuppari-operation:CreateApplication\n" +
76
+ "content-type;host;x-tuppari-operation\n" +
77
+ "8f2d5fe4a93000d3546e578d265fc936806f6ef6dc6f7ee87715e1a5c514c168"
78
+ Tuppari::Auth.create_string_to_sign(request, Time.new(2011, 2, 3, 4, 5, 6)).should(
79
+ eq("SHA256\n" +"20110202T190506Z\n" +"152176000cc08c7d9d0558bc3a50368aa38619a695ad20f50bec1344429cb315"))
80
+
81
+ end
82
+
83
+ it 'should have correct #create_signature' do
84
+ secret = 'secretKey1'
85
+ string_to_sign = "SHA256\n" +
86
+ "19700101T000000Z\n" +
87
+ "152176000cc08c7d9d0558bc3a50368aa38619a695ad20f50bec1344429cb315"
88
+ time = Time.new(1970, 1, 1, 0, 0, 0, "+00:00")
89
+ host = 'api.tuppari.com'
90
+ expected_signature = '4815ff1681a278e7c852902ea3604f17831a80a78dc0ff82f5142598a034509b'
91
+ (1...1000).each do |i|
92
+ signature = Tuppari::Auth.create_signature(secret, string_to_sign, time, host)
93
+ signature.should eq(expected_signature)
94
+ end
95
+
96
+ secret2 = 'secretKey2'
97
+ signature1 = Tuppari::Auth.create_signature(secret, string_to_sign, time, host)
98
+ signature2 = Tuppari::Auth.create_signature(secret2, string_to_sign, time, host)
99
+ signature2.should_not eq(signature1)
100
+ end
101
+
102
+ it 'should have correct #create_authorization_header' do
103
+ header = Tuppari::Auth.create_authorization_header(
104
+ :id => 'accessKeyId',
105
+ :secret => 'accessSecretKey',
106
+ :method => 'POST',
107
+ :host => 'api.tuppari.com',
108
+ :uri => '/test',
109
+ :query_string => 'a=v1&b=v2',
110
+ :headers => {
111
+ 'Host' => 'api.tuppari.com',
112
+ 'Content-Type' => 'application/json',
113
+ 'X-Tuppari-Operation' => 'CreateApplication'
114
+ },
115
+ :body_params => {
116
+ 'applicationName' => 'example1'
117
+ },
118
+ :request_time => Time.new(1970, 1, 1, 0, 0, 0, "+00:00")
119
+ )
120
+ header.should eq("HMAC-SHA256 Credential=accessKeyId,SignedHeaders=content-type;host;x-tuppari-operation,Signature=050f8711271747d4f63a3caa3ffb420e4cd5a0e9d9dda8ba7e4faad6794c40d0")
121
+ end
122
+
123
+ it 'should have correct #create_hmac_hash_value' do
124
+ result = Tuppari::Auth.create_hmac_hash_value('123', 'abc')
125
+ result.should eq('8f16771f9f8851b26f4d460fa17de93e2711c7e51337cb8a608a0f81e1c1b6ae')
126
+ end
127
+
128
+ end
@@ -0,0 +1,111 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'tuppari'
4
+
5
+ require 'logger'
6
+ require 'ruby-debug'
7
+
8
+ describe Tuppari do
9
+
10
+ account_name = ENV['TUPPARI_ACCOUNT_NAME']
11
+ password = ENV['TUPPARI_PASSWORD']
12
+
13
+ =begin
14
+
15
+ it "should create a new account" do
16
+ tuppari = Tuppari.new()
17
+ response = tuppari.create_account("account_name", "password")
18
+ puts response
19
+ end
20
+
21
+ it "should create a new account" do
22
+ tuppari = Tuppari.new(:account_name => account_name, :account_secret => account_secret)
23
+ response = tuppari.delete_application("application_name")
24
+ puts response
25
+ end
26
+
27
+ =end
28
+
29
+ it "should be created with account_name/account_secret" do
30
+ tuppari = Tuppari.new(
31
+ :account_name => account_name,
32
+ :account_secret => Tuppari.login(account_name, password).account_secret
33
+ )
34
+ tuppari.is_authenticated?.should eq(true)
35
+ end
36
+
37
+ it "should login" do
38
+ tuppari = Tuppari.new()
39
+ tuppari.is_authenticated?.should eq(false)
40
+ tuppari.login(account_name, password)
41
+ tuppari.is_authenticated?.should eq(true)
42
+ end
43
+
44
+ it "should raise Tuppari::AuthenticationError when creating a new applications without authentication" do
45
+ tuppari = Tuppari.new()
46
+ name = Time.now.tv_sec.to_s
47
+ begin
48
+ tuppari.create_application(name)
49
+ fail()
50
+ rescue Tuppari::AuthenticationError
51
+ end
52
+ end
53
+
54
+ it "should create a new application" do
55
+ tuppari = Tuppari.new(:log_level => Logger::WARN).login(account_name, password)
56
+ name = Time.now.tv_sec.to_s
57
+ app = tuppari.create_application(name)
58
+ app.name.should eq(name)
59
+ app.id.nil?.should eq(false)
60
+ app.access_key_id.nil?.should eq(false)
61
+ app.access_secret_key.nil?.should eq(false)
62
+ end
63
+
64
+ it "should raise Tuppari::AuthenticationError when getting my application list without authentication" do
65
+ tuppari = Tuppari.new()
66
+ begin
67
+ tuppari.get_application_list()
68
+ fail()
69
+ rescue Tuppari::AuthenticationError
70
+ end
71
+ end
72
+
73
+ it "should get my application list" do
74
+ tuppari = Tuppari.new(:log_level => Logger::WARN).login(account_name, password)
75
+ response = tuppari.get_application_list()
76
+ response.size.should > 0
77
+ end
78
+
79
+ it "should raise Tuppari::AuthenticationError when publishing messages without authentication" do
80
+ tuppari = Tuppari.new()
81
+ begin
82
+ response = tuppari.publish_message(
83
+ :application_name => 'tuppari-sample',
84
+ :channel => 'channel_name',
85
+ :event => 'event_name',
86
+ :message => 'Hello, Tuppari!'
87
+ )
88
+ fail()
89
+ rescue Tuppari::AuthenticationError
90
+ end
91
+ end
92
+
93
+
94
+ it "should publish messages" do
95
+ tuppari = Tuppari.new(:log_level => Logger::WARN).login(account_name, password)
96
+ response = tuppari.publish_message(
97
+ :application_name => 'tuppari-sample',
98
+ :channel => 'channel_name',
99
+ :event => 'event_name',
100
+ :message => 'Hello, Tuppari!'
101
+ )
102
+ response.size.should > 0
103
+ end
104
+
105
+ it "should get the service info" do
106
+ info = Tuppari.new().get_service_info()
107
+ info['name'].should eq("gyoji")
108
+ info['version'].nil?.should eq(false)
109
+ end
110
+
111
+ end
data/tuppari.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ $:.push File.expand_path("../lib", __FILE__)
4
+ require "tuppari/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "tuppari"
8
+ s.version = Tuppari::VERSION
9
+ s.authors = ["Kazuhiro Sera"]
10
+ s.email = ["seratch@gmail.com"]
11
+ s.homepage = "https://github.com/tuppari/tuppari-ruby"
12
+ s.summary = %q{Tuppari client for Ruby}
13
+ s.description = %q{Tuppari is an experimental implementation of unbreakable message broadcasting system using WebSocket and Amazon Web Services by @hakobera.}
14
+
15
+ s.rubyforge_project = "tuppari"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.required_ruby_version = '>= 1.9.0'
23
+
24
+ s.add_dependency('rest-client', '1.6.7')
25
+ s.add_dependency('json', '1.7.4')
26
+
27
+ end
28
+
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tuppari
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kazuhiro Sera
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - '='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.6.7
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - '='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.6.7
30
+ - !ruby/object:Gem::Dependency
31
+ name: json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - '='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.7.4
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - '='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.7.4
46
+ description: Tuppari is an experimental implementation of unbreakable message broadcasting
47
+ system using WebSocket and Amazon Web Services by @hakobera.
48
+ email:
49
+ - seratch@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - Gemfile
56
+ - README.md
57
+ - lib/tuppari.rb
58
+ - lib/tuppari/application.rb
59
+ - lib/tuppari/auth.rb
60
+ - lib/tuppari/authentication_error.rb
61
+ - lib/tuppari/client.rb
62
+ - lib/tuppari/client_error.rb
63
+ - lib/tuppari/server_url.rb
64
+ - lib/tuppari/version.rb
65
+ - spec/README.md
66
+ - spec/tuppari/auth_spec.rb
67
+ - spec/tuppari_spec.rb
68
+ - tuppari.gemspec
69
+ homepage: https://github.com/tuppari/tuppari-ruby
70
+ licenses: []
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: 1.9.0
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project: tuppari
89
+ rubygems_version: 1.8.24
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Tuppari client for Ruby
93
+ test_files:
94
+ - spec/README.md
95
+ - spec/tuppari/auth_spec.rb
96
+ - spec/tuppari_spec.rb