cargosocket 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 47b62251f65e525e81eacb09114d5a02de7960df
4
+ data.tar.gz: e6b19b1a1e83babb0afb075178e2bec8b1c9f90d
5
+ SHA512:
6
+ metadata.gz: c072d7ec21a201c6b95cf06fb9a77ec599241154312a2b0eac9ea5deda9893fde5bf549b8429c042cabf9215c7503d854c156713e9ccb07c746a199e19095ac8
7
+ data.tar.gz: cdaef4f77b65a5236bf721445658bc7e5fc37a23bf68bcdab03918aa9ef91177c8ccf32197fa73ed0ab572e4cde6d1c877e1deeadf511ecb68c577e524195c90
data/LICENSE.md ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2016, Matthias Geier
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,6 @@
1
+ require 'em-websocket'
2
+ require 'cargosocket/stream_adapters/cargobull_adapter'
3
+ require 'cargosocket/stream_adapters/e_m_channel_adapter'
4
+ require 'cargosocket/stream'
5
+ require 'cargobull'
6
+ require 'cargosocket/extensions/cargobull.rb'
@@ -0,0 +1,25 @@
1
+
2
+ module Cargobull
3
+ def self.streamer(cargoenv=env.get)
4
+ cargoenv[:session] = {}
5
+ cargoenv.freeze
6
+ Cargosocket::Stream.call(cargoenv)
7
+ end
8
+
9
+ module Dispatch
10
+ METHOD_MAP.merge!({
11
+ "CHANNELS" => :channels,
12
+ "REFERENCE" => :reference,
13
+ "SUBSCRIBE" => :subscribe,
14
+ "UNSUBSCRIBE" => :unsubscribe,
15
+ "ERROR" => :error,
16
+ "POP" => :pop,
17
+ "PUSH" => :push
18
+ })
19
+
20
+ def self.call_no_transform(env, *args)
21
+ dispatch(env, nil, nil, *args)
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,75 @@
1
+
2
+ module Cargosocket
3
+ module Stream
4
+ WS_OPT_KEYS = %w{host port debug secure secure_proxy tls_options
5
+ close_timeout outbound_limit}.map(&:to_sym)
6
+
7
+ def self.call(cargoenv)
8
+ raise "requires stream adapter" unless cargoenv[:adapter]
9
+
10
+ EM.run do
11
+ ws_config = WS_OPT_KEYS.reduce({}) do |acc, key|
12
+ acc[key] = cargoenv[key] if cargoenv.has_key?(key)
13
+ next acc
14
+ end
15
+ EM::WebSocket.run(ws_config){ |ws| config_socket(cargoenv, ws) }
16
+ end
17
+ end
18
+
19
+ def self.config_socket(cargoenv, ws)
20
+ ws.onopen do |w|
21
+ path = w.path.sub(/^\//, '')
22
+ periodic_ping(cargoenv, ws)
23
+ EM.add_timer(0.5){ setup_connection(cargoenv, ws, path, w.query) }
24
+ end
25
+ end
26
+
27
+ def self.periodic_ping(cargoenv, ws)
28
+ EM.add_periodic_timer(cargoenv[:ping_timer] || 5){ ws.ping }
29
+ end
30
+
31
+ def self.setup_connection(cargoenv, ws, path, query)
32
+ cb_adapter = StreamAdapters::CargobullAdapter
33
+
34
+ channels = cb_adapter.channels(cargoenv, path, query)
35
+ ref = cb_adapter.reference(cargoenv, path, query)
36
+ if channels && ref
37
+ state = cargoenv[:adapter].subscribe(*channels) do |channel, message|
38
+ cb_adapter.pop(cargoenv, path, ref, channel, message,
39
+ &ws.method(:send))
40
+ end
41
+
42
+ state.keys.each do |channel|
43
+ cb_adapter.subscribe(cargoenv, path, ref, channel) do |v|
44
+ cargoenv[:adapter].push(channel, v)
45
+ end
46
+ end
47
+
48
+ ws.onmessage do |message|
49
+ state.keys.each do |channel|
50
+ cb_adapter.push(cargoenv, path, ref, channel,
51
+ message.strip){ |v| cargoenv[:adapter].push(channel, v) }
52
+ end
53
+ end
54
+
55
+ ws.onerror do |error|
56
+ cargoenv[:adapter].unsubscribe(state) do |channel|
57
+ cb_adapter.error(cargoenv, path, ref, channel) do |v|
58
+ cargoenv[:adapter].push(channel, v)
59
+ end
60
+ end
61
+ end
62
+
63
+ ws.onclose do
64
+ cargoenv[:adapter].unsubscribe(state) do |channel|
65
+ cb_adapter.unsubscribe(cargoenv, path, ref, channel) do |v|
66
+ cargoenv[:adapter].push(channel, v)
67
+ end
68
+ end
69
+ end
70
+ else
71
+ ws.close(3001, channels.inspect || ref.to_s || "unknown")
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,49 @@
1
+
2
+ module Cargosocket
3
+ module StreamAdapters
4
+ module CargobullAdapter
5
+ def self.if_value(value)
6
+ return if value.last.nil?
7
+ yield(value.last)
8
+ end
9
+
10
+ def self.dispatch_to(m, *args)
11
+ Cargobull::Dispatch.send(m, *args)
12
+ end
13
+
14
+ def self.channels(cargoenv, path, query)
15
+ r = dispatch_to(:call_no_transform, cargoenv, "CHANNELS", path, query)
16
+ if r.first == 200 && r.last.is_a?(Array) && !r.last.empty?
17
+ r.last.map(&:to_sym)
18
+ end
19
+ end
20
+
21
+ def self.reference(cargoenv, path, query)
22
+ r = dispatch_to(:call_no_transform, cargoenv, "REFERENCE", path, query)
23
+ if r.first == 200
24
+ r.last
25
+ end
26
+ end
27
+
28
+ def self.subscribe(cargoenv, *args)
29
+ if_value(dispatch_to(:call, cargoenv, "SUBSCRIBE", *args), &Proc.new)
30
+ end
31
+
32
+ def self.unsubscribe(cargoenv, *args)
33
+ if_value(dispatch_to(:call, cargoenv, "UNSUBSCRIBE", *args), &Proc.new)
34
+ end
35
+
36
+ def self.error(cargoenv, *args)
37
+ if_value(dispatch_to(:call, cargoenv, "ERROR", *args), &Proc.new)
38
+ end
39
+
40
+ def self.push(cargoenv, *args)
41
+ if_value(dispatch_to(:call, cargoenv, "PUSH", *args), &Proc.new)
42
+ end
43
+
44
+ def self.pop(cargoenv, *args)
45
+ if_value(dispatch_to(:call, cargoenv, "POP", *args), &Proc.new)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,42 @@
1
+
2
+ module Cargosocket
3
+ module StreamAdapters
4
+ module EMChannelAdapter
5
+ CHANNELS = {}
6
+ DISPATCHERS = []
7
+
8
+ def self.dispatch(to)
9
+ # DISPATCHERS << to
10
+ end
11
+
12
+ def self.push(*to, message)
13
+ to.each do |channel|
14
+ if channel.is_a?(Symbol)
15
+ CHANNELS[channel].push(message) if CHANNELS.has_key?(channel)
16
+ else
17
+ # channel.push(message)
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.subscribe(*to)
23
+ callback = Proc.new
24
+ return to.reduce({}) do |acc, channel|
25
+ CHANNELS[channel] ||= EM::Channel.new
26
+ acc[channel] = CHANNELS[channel].subscribe(&callback.curry[channel])
27
+ next acc
28
+ end
29
+ end
30
+
31
+ def self.unsubscribe(from)
32
+ from.each do |channel, cid|
33
+ yield(channel)
34
+ CHANNELS[channel].unsubscribe(cid)
35
+ if CHANNELS[channel].num_subscribers == DISPATCHERS.count
36
+ CHANNELS.delete(channel)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1 @@
1
+ require 'cargosocket'
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cargosocket
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthias Geier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: em-websocket
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: cargobull
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
41
+ description:
42
+ email:
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - LICENSE.md
48
+ - lib/cargosocket.rb
49
+ - lib/cargosocket/extensions/cargobull.rb
50
+ - lib/cargosocket/stream.rb
51
+ - lib/cargosocket/stream_adapters/cargobull_adapter.rb
52
+ - lib/cargosocket/stream_adapters/e_m_channel_adapter.rb
53
+ - lib/cargosocket/test_helper.rb
54
+ homepage: https://github.com/matthias-geier/cargosocket
55
+ licenses:
56
+ - BSD-2
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.1.0
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.4.5.1
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Middleware to create a websocket service
78
+ test_files: []