sinapse 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e0830fca767543791482bb3d24747a07b2e8cd7e
4
+ data.tar.gz: e34f207abe290e1ea3f15a7f4625c011090f8e04
5
+ SHA512:
6
+ metadata.gz: 6ed6da3772bdf393658bf7de7780cfee57692847e1d6647215eaa3954d7242aba8888cf977f5f35e9959c1719474c473cf93899e4fa55406ff006c1bd727a837
7
+ data.tar.gz: 75b3ee32acbf69e8461374e8c36994ab7b88fbca86e10f7a4baf6222ee72c0fa09d579c1e10a3ec49b59a0deedabb775c026ee57ad4c16b0dd6527a75a7783ea
Binary file
@@ -0,0 +1 @@
1
+ �1v��?}��^=xŌ������a���c��8� Es��s�x��PO�>>?�l{�kl��*���ݬ 79����|�g�C�F ���h�_��J����β ۵�ó��W�"�ًѪ�|դ�8�e:)V;�]�*�� F���8�d��<�7\��7�h�!��:�5�ϰ6͍�(�B@t ��b3(�nD�"7�!���� �|A풝S�9���P듳�=2�*C�}�c (j(��~kV'8?�?��mX��`T
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - rbx-2.2.3
6
+ services:
7
+ - redis-server
8
+
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ platform :rbx do
6
+ gem 'rubysl-securerandom'
7
+
8
+ group :development do
9
+ gem 'rubysl-prettyprint'
10
+ end
11
+
12
+ group :test do
13
+ gem 'rubysl-singleton' # required by rake
14
+ gem 'rubysl-base64' # required by em-http-request
15
+ gem 'rubysl-mutex_m' # required by minitest 5.2
16
+ end
17
+ end
@@ -0,0 +1,101 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sinapse (0.0.1)
5
+ activesupport (>= 3.0.0)
6
+ connection_pool
7
+ goliath (>= 1.0.3)
8
+ hiredis
9
+ msgpack (>= 0.5.0)
10
+ redis (>= 3.0.6)
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ activesupport (4.1.0)
16
+ i18n (~> 0.6, >= 0.6.9)
17
+ json (~> 1.7, >= 1.7.7)
18
+ minitest (~> 5.1)
19
+ thread_safe (~> 0.1)
20
+ tzinfo (~> 1.1)
21
+ addressable (2.3.5)
22
+ ansi (1.4.3)
23
+ async-rack (0.5.1)
24
+ rack (~> 1.1)
25
+ builder (3.2.2)
26
+ connection_pool (1.2.0)
27
+ cookiejar (0.3.0)
28
+ em-http-request (1.1.1)
29
+ addressable (>= 2.3.4)
30
+ cookiejar
31
+ em-socksify (>= 0.3)
32
+ eventmachine (>= 1.0.3)
33
+ http_parser.rb (>= 0.6.0.beta.2)
34
+ em-socksify (0.3.0)
35
+ eventmachine (>= 1.0.0.beta.4)
36
+ em-synchrony (1.0.3)
37
+ eventmachine (>= 1.0.0.beta.1)
38
+ em-websocket (0.3.8)
39
+ addressable (>= 2.1.1)
40
+ eventmachine (>= 0.12.9)
41
+ eventmachine (1.0.3)
42
+ goliath (1.0.3)
43
+ async-rack
44
+ em-synchrony (>= 1.0.0)
45
+ em-websocket (= 0.3.8)
46
+ eventmachine (>= 1.0.0.beta.4)
47
+ http_parser.rb (= 0.6.0.beta.2)
48
+ log4r
49
+ multi_json
50
+ rack (>= 1.2.2)
51
+ rack-contrib
52
+ rack-respond_to
53
+ hashie (2.0.5)
54
+ hiredis (0.4.5)
55
+ http_parser.rb (0.6.0.beta.2)
56
+ i18n (0.6.9)
57
+ json (1.8.1)
58
+ log4r (1.1.10)
59
+ minitest (5.2.0)
60
+ minitest-reporters (1.0.0)
61
+ ansi
62
+ builder
63
+ minitest (>= 5.0)
64
+ powerbar
65
+ msgpack (0.5.8)
66
+ multi_json (1.10.0)
67
+ powerbar (1.0.11)
68
+ ansi (~> 1.4.0)
69
+ hashie (>= 1.1.0)
70
+ rack (1.5.2)
71
+ rack-accept-media-types (0.9)
72
+ rack-contrib (1.1.0)
73
+ rack (>= 0.9.1)
74
+ rack-respond_to (0.9.8)
75
+ rack-accept-media-types (>= 0.6)
76
+ rake (10.1.1)
77
+ redis (3.0.7)
78
+ rubysl-base64 (2.0.0)
79
+ rubysl-mutex_m (2.0.0)
80
+ rubysl-prettyprint (2.0.2)
81
+ rubysl-securerandom (2.0.0)
82
+ rubysl-singleton (2.0.0)
83
+ thread_safe (0.3.3)
84
+ tzinfo (1.1.0)
85
+ thread_safe (~> 0.1)
86
+
87
+ PLATFORMS
88
+ ruby
89
+
90
+ DEPENDENCIES
91
+ bundler
92
+ em-http-request
93
+ minitest (>= 5.2.0)
94
+ minitest-reporters
95
+ rake
96
+ rubysl-base64
97
+ rubysl-mutex_m
98
+ rubysl-prettyprint
99
+ rubysl-securerandom
100
+ rubysl-singleton
101
+ sinapse!
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Julien Portalier
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,173 @@
1
+ # Sinapse
2
+
3
+ EventSource service for pushing messages written in Ruby.
4
+
5
+ Pushing messages to the browser or any other kind or client should be as easy as
6
+ posting from a browser. The technology is there with the PUB/SUB solution
7
+ offered by Redis and the simple server push protocol allowed by EventSource
8
+ (Server-Sent Events) over regular HTTP.
9
+
10
+ Sinapse is a push service running in an event-loop (thanks to Goliath and
11
+ EventMachine) and takes care of pushing all your events, and to deliver them to
12
+ whoever is allowed to receive them.
13
+
14
+
15
+ ## How it works
16
+
17
+ A user connects to the Sinapse server using a token. That token will be
18
+ associated to a list of channels that the user is authorized to listen to. That
19
+ list of channels can be updated at any time and will be applied live to existing
20
+ connection, so users will only ever receive what they are allowed to receive.
21
+
22
+ This is different from [Faye](http://faye.jcoglan.com) for example, which is
23
+ a PUB/SUB solution to have clients subscribe and publish to whatever channels
24
+ they want. Sinapse is a push service to notify clients about changes that
25
+ happened on the backend, and the list of authorized channels is thus kept on
26
+ the server.
27
+
28
+
29
+ ## Features
30
+
31
+ Sinapse is still a work in progress, and the API subject to changes, but it
32
+ already features:
33
+
34
+ - A solid architecture (Goliath + EventMachine + Redis).
35
+ - EventSource (Server-Sent Events) server with support for CORS requests,
36
+ authentication and a live updating list of channels.
37
+ - Keep EventSource connection alive by sending comments are regular intervals.
38
+ - Ruby library to manipulate user channels, authentication and to publish
39
+ messages.
40
+
41
+ TODO:
42
+
43
+ - Support [Yaffle EventSource polyfill](https://github.com/Yaffle/EventSource)
44
+ (for Internet Explorer support)
45
+ - Support for Web Sockets alongside EventSource (for native IE10+ support)
46
+ - Retain messages with some expiry to avoid missing messages because of
47
+ network connection problems.
48
+
49
+
50
+ ## Requirements
51
+
52
+ Sinapse is compatible and actively tested with Ruby 1.9.3+ and Rubinius 2.2+. It
53
+ requires a Redis 2.2+ server instance. Sinapse should be compatible with Ubuntu
54
+ 12.04 LTS out of the box. It may be compatible with older versions of Ruby,
55
+ Rubinius or Redis but this isn't supported.
56
+
57
+ Sinapse comes with a Ruby library, but it can be used from other languages,
58
+ because all the communication to the Sinapse server happens through Redis. The
59
+ protocol hasn't been formalized yet and you will have to check the ruby
60
+ implementation and test suite to understand it.
61
+
62
+
63
+ ## Usage
64
+
65
+ Declare sinapse in your Gemfile and run `bundle`:
66
+
67
+ ```ruby
68
+ gem "sinapse", github: "ysbaddaden/sinapse"
69
+ ```
70
+
71
+ You may now start the server with `bundle exec sinapse` or generate a binstub
72
+ with `bundle binstubs sinapse` then start the server with `bin/sinapse`.
73
+
74
+ Once started the server will be available on http://0.0.0.0:9000/ by default.
75
+ It can be configured to run on a UNIX socket or a specific host and port. Run
76
+ `sinapse --help` or read the Goliath documentation for more information.
77
+
78
+ ### Configuration
79
+
80
+ The Sinapse server may be configured using environment variables:
81
+
82
+ - `SINAPSE_CORS_ORIGIN` — restrict origins for CORS browser requests (defaults to `*`).
83
+ - `SINAPSE_KEEP_ALIVE` — send a comment every n seconds to keep the connection alive (defaults to `15`).
84
+ - `SINAPSE_RETRY` — EventSource retry parameter (defaults to `5`).
85
+ - `SINAPSE_CHANNEL_EVENT` — set the channel name as the event type to sent messages.
86
+
87
+ Sinapse (both the client and the server) will connect to the Redis instance
88
+ defined in the `REDIS_URL` environment variable and fallback to the default
89
+ `redis://localhost:6379/0`.
90
+
91
+ ### Authenticate
92
+
93
+ Include `Sinapse` into the subjects that will authenticate to the Sinapse
94
+ server. The example below uses ActiveRecord but Sinapse should work with any
95
+ Ruby class, as long as it responds to `#to_param`.
96
+
97
+ ```ruby
98
+ class User < ActiveRecord::Base
99
+ include Sinapse
100
+ end
101
+ ```
102
+
103
+ Once your subjects are defined, you must generate tokens for the subjects, then
104
+ declare a list of channels they are authorized to access. You are responsible
105
+ for generating and replacing the token when your application requires it. For
106
+ example you may create the token when creating the user:
107
+
108
+ ```ruby
109
+ class User < ActiveRecord::Base
110
+ include Sinapse
111
+ end
112
+
113
+ # create the token and initialize channels
114
+ user = User.create(attributes)
115
+ token = user.sinapse.auth.generate
116
+
117
+ # destroy the token and the user channels
118
+ sinapse.auth.clear
119
+ ```
120
+
121
+ You may now connect to `http://localhost:9000/?access_token=<token>` but it
122
+ will return a `401 Unauthorized` because the connected subject doesn't have any
123
+ channel to listen to.
124
+
125
+ A 401 Unauthorized HTTP status will be returned whenever an `access_token` is
126
+ invalid or the list of channels is empty. The connection may also be closed
127
+ immediately whenever the list of channels gets emptied.
128
+
129
+ ### Channels
130
+
131
+ You may now add and remove the channels that a user may be notified of at any
132
+ time. Usually a channel will be a class instance. Include `Sinapse::Publishable`
133
+ into the classes that may publish events, add them to the authorized channels of
134
+ a user, then publish your messages through the class:
135
+
136
+ ```ruby
137
+ class Room < ActiveRecord::Base
138
+ include Sinapse::Publishable
139
+ end
140
+
141
+ # add the channel to a user's channel list
142
+ room = Room.find(params[:id])
143
+ user.sinapse.add_channel(room)
144
+
145
+ # publish a message (the user will receive it)
146
+ room.publish(room.to_json)
147
+
148
+ # remove the channel
149
+ user.sinapse.remove_channel(room)
150
+
151
+ # publish another message (the user won't receive it)
152
+ room.publish(room.to_json)
153
+ ```
154
+
155
+
156
+ ## Example
157
+
158
+ Please see the [example](https://github.com/ysbaddaden/sinapse/tree/master/example)
159
+ for up to date working code. To try it start the Sinapse server with `bin/sinapse`
160
+ then the example rack application. Open http://localhost:3000 in different
161
+ browsers, and start a chat!
162
+
163
+
164
+ ## Author
165
+
166
+ - Julien Portalier
167
+
168
+
169
+ ## License
170
+
171
+ Distributed under the MIT License.
172
+ See [LICENSE](LICENSE.m://github.com/ysbaddaden/sinapse/blob/master/LICENSE).
173
+
@@ -0,0 +1,11 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ task :default => :test
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ t.verbose = true
10
+ end
11
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,10 @@
1
+ #! /usr/bin/env ruby
2
+ $:.unshift File.expand_path("../../lib", File.realpath(__FILE__))
3
+
4
+ RACK_ENV ||= ENV['RACK_ENV'] ||= 'development'
5
+
6
+ require 'bundler/setup'
7
+ Bundler.require(:default, RACK_ENV)
8
+
9
+ require 'sinapse/server'
10
+
@@ -0,0 +1,21 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDeDCCAmCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBBMQ8wDQYDVQQDDAZqdWxp
3
+ ZW4xGTAXBgoJkiaJk/IsZAEZFglwb3J0YWxpZXIxEzARBgoJkiaJk/IsZAEZFgNj
4
+ b20wHhcNMTQwMTE0MjIzMTQ4WhcNMTUwMTE0MjIzMTQ4WjBBMQ8wDQYDVQQDDAZq
5
+ dWxpZW4xGTAXBgoJkiaJk/IsZAEZFglwb3J0YWxpZXIxEzARBgoJkiaJk/IsZAEZ
6
+ FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpxWuWRJXEz2+p
7
+ 2EW4NOPzkKloRLWoj+WQnqhQKT46GbH3ToDId8AMELTDIKpTQFiG2ty6D7S4IBFv
8
+ 7ceFKNk/EJc17mSYE1DzrtItor2/eeGC1zeNfvLjyDtyHKyKUZ891C1D0so5coUx
9
+ 2YbDW5npFkJkPaA5GneH7DFaCoIFLrD7ekbzaZAjlH+EH2fhd1XLhSsPEIiE+OnD
10
+ ilWnsPoRJAZwQOiVAtvh7xuc+29uSNndIIm2rU00SxbJnzsAq9ZddwPpMU/UcQpD
11
+ 4gCBCaNGzrLz4+upQdYEOuggM7rR3P934qfhIwb+aRGglqdNunmUrdCuhsGXrxq2
12
+ FvqwDvFZAgMBAAGjezB5MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
13
+ BBQoESDCnNz3LmbpUzOrGeXOpk9sqjAfBgNVHREEGDAWgRRqdWxpZW5AcG9ydGFs
14
+ aWVyLmNvbTAfBgNVHRIEGDAWgRRqdWxpZW5AcG9ydGFsaWVyLmNvbTANBgkqhkiG
15
+ 9w0BAQUFAAOCAQEAML4w0F/VF0gi5JqMqYSO05TakAauG8jQX0hov5H8M0Xhl79G
16
+ BdUllH0QEw0cP6J2g46zAk0FGHIGthx0OKKi5YMYTs/KPqOVIAcJslt2sGIC1Ukm
17
+ wpOWIg1XMe68+JVTktBKcBFAvc0pLtty1TgdSd2wr7KQgfmBU9I8G6AoPYhJOhkG
18
+ SHTTSX3ms2/XePuSnyOfir/AQC7U0NalnKLNdwY9gkEdNwiTf5Ga/lZVDQ607bow
19
+ KVqCN//9bevjMk5OiMi9X3Wu/GtVWDwC6OTWFWKd54KgbuWlakO8LC1SMmStnCIF
20
+ W4qpyMWMZMcB4ZN/0mUVzY5xwrislBtsmQVUSw==
21
+ -----END CERTIFICATE-----
@@ -0,0 +1,3 @@
1
+ Rainbows! do
2
+ use :EventMachine
3
+ end
@@ -0,0 +1,22 @@
1
+ # http://en.wikibooks.org/wiki/Ruby_Programming/RubyGems#How_to_install_different_versions_of_gems_depending_on_which_version_of_ruby_the_installee_is_using
2
+ require 'rubygems'
3
+ require 'rubygems/command.rb'
4
+ require 'rubygems/dependency_installer.rb'
5
+
6
+ begin
7
+ Gem::Command.build_args = ARGV
8
+ rescue NoMethodError
9
+ end
10
+
11
+ inst = Gem::DependencyInstaller.new
12
+
13
+ begin
14
+ if RUBY_ENGINE == "rbx"
15
+ inst.install "rubysl-securerandom"
16
+ #inst.install "rubysl-base64"
17
+ end
18
+ rescue
19
+ exit 1
20
+ end
21
+
22
+ exit 0
@@ -0,0 +1,42 @@
1
+ require 'sinapse/version'
2
+ require 'sinapse/authentication'
3
+ require 'sinapse/channels'
4
+ require 'sinapse/publishable'
5
+ require 'connection_pool'
6
+ require 'redis'
7
+ require 'hiredis'
8
+
9
+ module Sinapse
10
+ def sinapse
11
+ @sinapse ||= Sinapse::Channels.new(self)
12
+ end
13
+
14
+ class << self
15
+ def redis(&block)
16
+ raise ArgumentError, "requires a block" unless block
17
+ @redis ||= ConnectionPool.new(pool_options) { Redis.new(url: config[:url]) }
18
+ @redis.with(&block)
19
+ end
20
+
21
+ def redis=(redis)
22
+ raise ArgumentError, "requires a ConnectionPool" unless redis.kind_of?(ConnectionPool)
23
+ @redis = redis
24
+ end
25
+
26
+ def config
27
+ @config ||= {
28
+ size: 5,
29
+ timeout: 5,
30
+ url: ENV['REDIS_URL'] || 'redis://localhost:6379/0'
31
+ }
32
+ end
33
+
34
+ def config=(options)
35
+ @config = config.merge(options.symbolize_keys)
36
+ end
37
+
38
+ def pool_options
39
+ @pool_options ||= { size: config[:size], timeout: config[:timeout] }
40
+ end
41
+ end
42
+ end