pakyow-realtime 0.11.3 → 1.0.0.rc1
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 +5 -5
- data/{pakyow-realtime/CHANGELOG.md → CHANGELOG.md} +5 -0
- data/LICENSE +4 -0
- data/{pakyow-realtime/README.md → README.md} +1 -2
- data/lib/pakyow/environment/realtime/config.rb +29 -0
- data/lib/pakyow/realtime/actions/upgrader.rb +29 -0
- data/lib/pakyow/realtime/behavior/config.rb +42 -0
- data/lib/pakyow/realtime/behavior/rendering/install_websocket.rb +57 -0
- data/lib/pakyow/realtime/behavior/serialization.rb +42 -0
- data/lib/pakyow/realtime/behavior/server.rb +42 -0
- data/lib/pakyow/realtime/behavior/silencing.rb +25 -0
- data/lib/pakyow/realtime/channel.rb +23 -0
- data/lib/pakyow/realtime/context.rb +38 -0
- data/lib/pakyow/realtime/framework.rb +49 -0
- data/lib/pakyow/realtime/helpers/broadcasting.rb +13 -0
- data/lib/pakyow/realtime/helpers/socket.rb +13 -0
- data/lib/pakyow/realtime/helpers/subscriptions.rb +35 -0
- data/lib/pakyow/realtime/server/adapters/memory.rb +127 -0
- data/lib/pakyow/realtime/server/adapters/redis.rb +277 -0
- data/lib/pakyow/realtime/server.rb +152 -0
- data/lib/pakyow/realtime/websocket.rb +157 -0
- data/lib/pakyow/realtime.rb +13 -0
- metadata +73 -44
- data/pakyow-realtime/LICENSE +0 -20
- data/pakyow-realtime/lib/pakyow/realtime/config.rb +0 -20
- data/pakyow-realtime/lib/pakyow/realtime/connection.rb +0 -18
- data/pakyow-realtime/lib/pakyow/realtime/context.rb +0 -68
- data/pakyow-realtime/lib/pakyow/realtime/delegate.rb +0 -112
- data/pakyow-realtime/lib/pakyow/realtime/exceptions.rb +0 -6
- data/pakyow-realtime/lib/pakyow/realtime/ext/request.rb +0 -10
- data/pakyow-realtime/lib/pakyow/realtime/helpers.rb +0 -40
- data/pakyow-realtime/lib/pakyow/realtime/hooks.rb +0 -41
- data/pakyow-realtime/lib/pakyow/realtime/message_handler.rb +0 -57
- data/pakyow-realtime/lib/pakyow/realtime/message_handlers/call_route.rb +0 -34
- data/pakyow-realtime/lib/pakyow/realtime/message_handlers/ping.rb +0 -8
- data/pakyow-realtime/lib/pakyow/realtime/redis_subscription.rb +0 -61
- data/pakyow-realtime/lib/pakyow/realtime/registries/redis_registry.rb +0 -107
- data/pakyow-realtime/lib/pakyow/realtime/registries/simple_registry.rb +0 -40
- data/pakyow-realtime/lib/pakyow/realtime/websocket.rb +0 -209
- data/pakyow-realtime/lib/pakyow/realtime.rb +0 -19
- data/pakyow-realtime/lib/pakyow-realtime.rb +0 -1
metadata
CHANGED
@@ -1,132 +1,161 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pakyow-realtime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan Powell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: pakyow-
|
14
|
+
name: pakyow-core
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 1.0.0.rc1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 1.0.0.rc1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: pakyow-
|
28
|
+
name: pakyow-presenter
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.0.rc1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.0.rc1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pakyow-routing
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - '='
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
47
|
+
version: 1.0.0.rc1
|
34
48
|
type: :runtime
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - '='
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
54
|
+
version: 1.0.0.rc1
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: pakyow-support
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.0.rc1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.0.0.rc1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: async-websocket
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
44
72
|
requirements:
|
45
73
|
- - "~>"
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
75
|
+
version: 0.12.1
|
48
76
|
type: :runtime
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
82
|
+
version: 0.12.1
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
84
|
+
name: concurrent-ruby
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
58
86
|
requirements:
|
59
87
|
- - "~>"
|
60
88
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
89
|
+
version: '1.1'
|
62
90
|
type: :runtime
|
63
91
|
prerelease: false
|
64
92
|
version_requirements: !ruby/object:Gem::Requirement
|
65
93
|
requirements:
|
66
94
|
- - "~>"
|
67
95
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
96
|
+
version: '1.1'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
98
|
+
name: redis
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
72
100
|
requirements:
|
73
101
|
- - "~>"
|
74
102
|
- !ruby/object:Gem::Version
|
75
|
-
version: '1
|
103
|
+
version: '4.1'
|
76
104
|
type: :runtime
|
77
105
|
prerelease: false
|
78
106
|
version_requirements: !ruby/object:Gem::Requirement
|
79
107
|
requirements:
|
80
108
|
- - "~>"
|
81
109
|
- !ruby/object:Gem::Version
|
82
|
-
version: '1
|
110
|
+
version: '4.1'
|
83
111
|
description: WebSockets and realtime channels for Pakyow
|
84
112
|
email: bryan@metabahn.com
|
85
113
|
executables: []
|
86
114
|
extensions: []
|
87
115
|
extra_rdoc_files: []
|
88
116
|
files:
|
89
|
-
-
|
90
|
-
-
|
91
|
-
-
|
92
|
-
- pakyow
|
93
|
-
-
|
94
|
-
-
|
95
|
-
-
|
96
|
-
-
|
97
|
-
-
|
98
|
-
-
|
99
|
-
-
|
100
|
-
-
|
101
|
-
-
|
102
|
-
-
|
103
|
-
-
|
104
|
-
-
|
105
|
-
-
|
106
|
-
-
|
107
|
-
-
|
108
|
-
-
|
109
|
-
|
117
|
+
- CHANGELOG.md
|
118
|
+
- LICENSE
|
119
|
+
- README.md
|
120
|
+
- lib/pakyow/environment/realtime/config.rb
|
121
|
+
- lib/pakyow/realtime.rb
|
122
|
+
- lib/pakyow/realtime/actions/upgrader.rb
|
123
|
+
- lib/pakyow/realtime/behavior/config.rb
|
124
|
+
- lib/pakyow/realtime/behavior/rendering/install_websocket.rb
|
125
|
+
- lib/pakyow/realtime/behavior/serialization.rb
|
126
|
+
- lib/pakyow/realtime/behavior/server.rb
|
127
|
+
- lib/pakyow/realtime/behavior/silencing.rb
|
128
|
+
- lib/pakyow/realtime/channel.rb
|
129
|
+
- lib/pakyow/realtime/context.rb
|
130
|
+
- lib/pakyow/realtime/framework.rb
|
131
|
+
- lib/pakyow/realtime/helpers/broadcasting.rb
|
132
|
+
- lib/pakyow/realtime/helpers/socket.rb
|
133
|
+
- lib/pakyow/realtime/helpers/subscriptions.rb
|
134
|
+
- lib/pakyow/realtime/server.rb
|
135
|
+
- lib/pakyow/realtime/server/adapters/memory.rb
|
136
|
+
- lib/pakyow/realtime/server/adapters/redis.rb
|
137
|
+
- lib/pakyow/realtime/websocket.rb
|
138
|
+
homepage: https://pakyow.org
|
110
139
|
licenses:
|
111
|
-
-
|
140
|
+
- LGPL-3.0
|
112
141
|
metadata: {}
|
113
142
|
post_install_message:
|
114
143
|
rdoc_options: []
|
115
144
|
require_paths:
|
116
|
-
-
|
145
|
+
- lib
|
117
146
|
required_ruby_version: !ruby/object:Gem::Requirement
|
118
147
|
requirements:
|
119
148
|
- - ">="
|
120
149
|
- !ruby/object:Gem::Version
|
121
|
-
version: 2.
|
150
|
+
version: 2.5.0
|
122
151
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
152
|
requirements:
|
124
|
-
- - "
|
153
|
+
- - ">"
|
125
154
|
- !ruby/object:Gem::Version
|
126
|
-
version:
|
155
|
+
version: 1.3.1
|
127
156
|
requirements: []
|
128
157
|
rubyforge_project:
|
129
|
-
rubygems_version: 2.
|
158
|
+
rubygems_version: 2.7.6
|
130
159
|
signing_key:
|
131
160
|
specification_version: 4
|
132
161
|
summary: Pakyow Realtime
|
data/pakyow-realtime/LICENSE
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
Copyright (c) 2015 Bryan Powell
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require_relative 'registries/simple_registry'
|
2
|
-
require_relative 'registries/redis_registry'
|
3
|
-
|
4
|
-
Pakyow::Config.register :realtime do |config|
|
5
|
-
# The registry to use when keeping up with connections.
|
6
|
-
config.opt :registry, Pakyow::Realtime::SimpleRegistry
|
7
|
-
|
8
|
-
# The Redis config hash.
|
9
|
-
config.opt :redis, url: 'redis://127.0.0.1:6379'
|
10
|
-
|
11
|
-
# The key used to keep track of channels in Redis.
|
12
|
-
config.opt :redis_key, 'pw:channels'
|
13
|
-
|
14
|
-
# Whether or not realtime should be enabled.
|
15
|
-
config.opt :enabled, true
|
16
|
-
end.env :development do |opts|
|
17
|
-
opts.registry = Pakyow::Realtime::SimpleRegistry
|
18
|
-
end.env :production do |opts|
|
19
|
-
opts.registry = Pakyow::Realtime::RedisRegistry
|
20
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require_relative 'config'
|
2
|
-
|
3
|
-
module Pakyow
|
4
|
-
module Realtime
|
5
|
-
# Represents a realtime connection (e.g. websocket).
|
6
|
-
#
|
7
|
-
# @api private
|
8
|
-
class Connection
|
9
|
-
def delegate
|
10
|
-
Delegate.instance
|
11
|
-
end
|
12
|
-
|
13
|
-
def logger
|
14
|
-
Pakyow.logger
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require_relative 'websocket'
|
2
|
-
require_relative 'config'
|
3
|
-
|
4
|
-
module Pakyow
|
5
|
-
module Realtime
|
6
|
-
# Deals with realtime connections in context of an app. Instances are
|
7
|
-
# returned by the `socket` helper method during routing.
|
8
|
-
#
|
9
|
-
# @api public
|
10
|
-
class Context
|
11
|
-
# @api private
|
12
|
-
def initialize(app)
|
13
|
-
@app = app
|
14
|
-
end
|
15
|
-
|
16
|
-
# Subscribe the current session's connection to one or more channels.
|
17
|
-
#
|
18
|
-
# @api public
|
19
|
-
def subscribe(*channels)
|
20
|
-
channels = Array.ensure(channels).flatten
|
21
|
-
fail ArgumentError if channels.empty?
|
22
|
-
|
23
|
-
delegate.subscribe(
|
24
|
-
@app.socket_digest(@app.socket_connection_id),
|
25
|
-
channels
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
# Unsubscribe the current session's connection to one or more channels.
|
30
|
-
#
|
31
|
-
# @api public
|
32
|
-
def unsubscribe(*channels)
|
33
|
-
channels = Array.ensure(channels).flatten
|
34
|
-
fail ArgumentError if channels.empty?
|
35
|
-
|
36
|
-
delegate.unsubscribe(
|
37
|
-
@app.socket_digest(@app.socket_connection_id),
|
38
|
-
channels
|
39
|
-
)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Push a message down one or more channels.
|
43
|
-
#
|
44
|
-
# @api public
|
45
|
-
def push(msg, *channels)
|
46
|
-
channels = Array.ensure(channels).flatten
|
47
|
-
fail ArgumentError if channels.empty?
|
48
|
-
|
49
|
-
delegate.push(msg, channels)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Push a message down a channel directed at a specific client,
|
53
|
-
# identified by key.
|
54
|
-
#
|
55
|
-
# @api public
|
56
|
-
def push_message_to_socket_with_key(msg, channel, key, propagated = false)
|
57
|
-
delegate.push_message_to_socket_with_key(msg, channel, key, propagated)
|
58
|
-
end
|
59
|
-
|
60
|
-
# Returns an instance of the connection delegate.
|
61
|
-
#
|
62
|
-
# @api private
|
63
|
-
def delegate
|
64
|
-
Delegate.instance
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,112 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module Realtime
|
3
|
-
# A singleton for delegating socket traffic using the configured registry.
|
4
|
-
#
|
5
|
-
# @api private
|
6
|
-
class Delegate
|
7
|
-
include Singleton
|
8
|
-
|
9
|
-
attr_reader :registry, :connections, :channels
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
@registry = Config.realtime.registry.instance
|
13
|
-
|
14
|
-
@connections = {}
|
15
|
-
@channels = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
# Registers a websocket instance with a unique key.
|
19
|
-
def register(key, connection)
|
20
|
-
@connections[key] = connection
|
21
|
-
|
22
|
-
channels = registry.channels_for_key(key)
|
23
|
-
|
24
|
-
channels.each do |channel|
|
25
|
-
next if connection.nil?
|
26
|
-
@channels[channel] ||= []
|
27
|
-
|
28
|
-
next if @channels[channel].include?(connection)
|
29
|
-
@channels[channel] << connection
|
30
|
-
end
|
31
|
-
|
32
|
-
registry.subscribe_for_propagation(channels, key) if registry.propagates?
|
33
|
-
end
|
34
|
-
|
35
|
-
# Unregisters a connection by its key.
|
36
|
-
def unregister(key)
|
37
|
-
registry.unregister_key(key)
|
38
|
-
|
39
|
-
connection = @connections.delete(key)
|
40
|
-
@channels.each do |_channel, connections|
|
41
|
-
connections.delete(connection)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Subscribes a websocket identified by its key to one or more channels.
|
46
|
-
def subscribe(key, channels)
|
47
|
-
registry.subscribe_to_channels_for_key(channels, key)
|
48
|
-
|
49
|
-
# register the connection again since we've added channels
|
50
|
-
register(key, @connections[key])
|
51
|
-
end
|
52
|
-
|
53
|
-
# Unsubscribes a websocket identified by its key to one or more channels.
|
54
|
-
def unsubscribe(key, channels)
|
55
|
-
registry.unsubscribe_to_channels_for_key(channels, key)
|
56
|
-
end
|
57
|
-
|
58
|
-
# Pushes a message down channels from server to client.
|
59
|
-
def push(message, channels)
|
60
|
-
if registry.propagates? && !propagated?(message)
|
61
|
-
return propagate(message, channels)
|
62
|
-
elsif propagated?(message)
|
63
|
-
message.delete(:__propagated)
|
64
|
-
end
|
65
|
-
|
66
|
-
# push to this instances connections
|
67
|
-
channels.each do |channel_query|
|
68
|
-
connections_for_channel(channel_query).each_pair do |channel, conns|
|
69
|
-
conns.each do |connection|
|
70
|
-
connection.push(payload: message, channel: channel)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Pushes a message down a channel to a specific client (identified by key).
|
77
|
-
def push_message_to_socket_with_key(message, channel, key, propagated = false)
|
78
|
-
return if key.nil? || key.empty?
|
79
|
-
|
80
|
-
if registry.propagates? && !propagated
|
81
|
-
return registry.push_message_to_socket_with_key(message, channel, key)
|
82
|
-
else
|
83
|
-
connection = @connections.find { |_, connection|
|
84
|
-
connection and connection.key == key
|
85
|
-
}
|
86
|
-
|
87
|
-
if connection
|
88
|
-
connection[1].push(payload: message, channel: channel)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def propagate(message, channels)
|
96
|
-
registry.propagate(message, channels)
|
97
|
-
end
|
98
|
-
|
99
|
-
def propagated?(message)
|
100
|
-
message.include?(:__propagated) || message.include?('__propagated')
|
101
|
-
end
|
102
|
-
|
103
|
-
def connections_for_channel(channel_query)
|
104
|
-
regexp = Regexp.new("^#{channel_query.to_s.gsub('*', '([^;]*)')}$")
|
105
|
-
|
106
|
-
@channels.select { |channel, _conns|
|
107
|
-
channel.match(regexp)
|
108
|
-
}
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module Helpers
|
3
|
-
# Returns a working realtime context for the current app context.
|
4
|
-
#
|
5
|
-
# @api public
|
6
|
-
def socket
|
7
|
-
Realtime::Context.new(self)
|
8
|
-
end
|
9
|
-
|
10
|
-
# Returns the session's unique realtime key.
|
11
|
-
#
|
12
|
-
# @api private
|
13
|
-
def socket_key
|
14
|
-
return params[:socket_key] if params[:socket_key]
|
15
|
-
session[:socket_key] ||= SecureRandom.hex(32)
|
16
|
-
end
|
17
|
-
|
18
|
-
# Returns the unique connection id for this request lifecycle.
|
19
|
-
#
|
20
|
-
# @api private
|
21
|
-
def socket_connection_id
|
22
|
-
return params[:socket_connection_id] if params[:socket_connection_id]
|
23
|
-
@socket_connection_id ||= SecureRandom.hex(32)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Returns a digest created from the connection id and socket_key.
|
27
|
-
#
|
28
|
-
# @api private
|
29
|
-
def socket_digest(socket_connection_id)
|
30
|
-
Digest::SHA1.hexdigest("--#{socket_key}--#{socket_connection_id}--")
|
31
|
-
end
|
32
|
-
|
33
|
-
module App
|
34
|
-
# @api private
|
35
|
-
def socket
|
36
|
-
Realtime::Context.new(self)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
Pakyow::App.before :route do
|
2
|
-
# we want to hijack websocket requests
|
3
|
-
#
|
4
|
-
if req.env['HTTP_UPGRADE'] && req.env['HTTP_UPGRADE'].casecmp('websocket') == 0
|
5
|
-
if Pakyow::Config.realtime.enabled
|
6
|
-
socket_connection_id = params[:socket_connection_id]
|
7
|
-
socket_digest = socket_digest(socket_connection_id)
|
8
|
-
|
9
|
-
begin
|
10
|
-
conn = Pakyow::Realtime::Websocket.new(req, socket_digest)
|
11
|
-
rescue Pakyow::Realtime::HandshakeError => e
|
12
|
-
logger.error e.message
|
13
|
-
res.status = 400
|
14
|
-
halt
|
15
|
-
end
|
16
|
-
|
17
|
-
# register the connection with a unique key
|
18
|
-
Pakyow::Realtime::Delegate.instance.register(socket_digest, conn)
|
19
|
-
|
20
|
-
# tell the connection that it's registered
|
21
|
-
conn.registered
|
22
|
-
end
|
23
|
-
|
24
|
-
halt
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
Pakyow::App.after :process do
|
29
|
-
# mixin the socket connection id into the body tag
|
30
|
-
# this id is used by pakyow.js to idenfity itself with the server
|
31
|
-
#
|
32
|
-
if response.header['Content-Type'].include?('text/html') && Pakyow::Config.realtime.enabled
|
33
|
-
next if !response.body.is_a?(Array)
|
34
|
-
|
35
|
-
body = response.body.first
|
36
|
-
next if body.nil?
|
37
|
-
|
38
|
-
mixin = '<body data-socket-connection-id="' + socket_connection_id + '"'
|
39
|
-
body.gsub!(/<body/, mixin)
|
40
|
-
end
|
41
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
require_relative 'exceptions'
|
2
|
-
|
3
|
-
module Pakyow
|
4
|
-
module Realtime
|
5
|
-
# Convenience method for registering a new message handler.
|
6
|
-
#
|
7
|
-
# @api public
|
8
|
-
def self.handler(name, &block)
|
9
|
-
MessageHandler.register(name, &block)
|
10
|
-
end
|
11
|
-
|
12
|
-
# A message handler registry. Handlers subscribe to some action and handle
|
13
|
-
# incoming messages for that action, returning a response.
|
14
|
-
#
|
15
|
-
# @api private
|
16
|
-
class MessageHandler
|
17
|
-
# Registers a handler for some action name.
|
18
|
-
#
|
19
|
-
# @api private
|
20
|
-
def self.register(name, &block)
|
21
|
-
handlers[name.to_sym] = block
|
22
|
-
end
|
23
|
-
|
24
|
-
# Calls a handler for a received websocket message.
|
25
|
-
#
|
26
|
-
# @api private
|
27
|
-
def self.handle(message, session)
|
28
|
-
id = message.fetch('id') {
|
29
|
-
fail ArgumentError, "Expected message to contain key 'id'"
|
30
|
-
}
|
31
|
-
|
32
|
-
action = message.fetch('action') {
|
33
|
-
fail ArgumentError, "Expected message to contain key 'action'"
|
34
|
-
}
|
35
|
-
|
36
|
-
handler = handlers.fetch(action.to_sym) {
|
37
|
-
fail MissingMessageHandler, "No message handler named #{action}"
|
38
|
-
}
|
39
|
-
|
40
|
-
handler.call(message, session, id: id)
|
41
|
-
end
|
42
|
-
|
43
|
-
# Resets the message handlers.
|
44
|
-
#
|
45
|
-
# @api private
|
46
|
-
def self.reset
|
47
|
-
@handlers = nil
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def self.handlers
|
53
|
-
@handlers ||= {}
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# Calls an app route and returns a response, just like an HTTP request!
|
2
|
-
#
|
3
|
-
Pakyow::Realtime.handler :'call-route' do |message, session, response|
|
4
|
-
env = Rack::MockRequest.env_for(message['uri'], method: message['method'])
|
5
|
-
env['pakyow.socket'] = true
|
6
|
-
env['pakyow.data'] = message['input']
|
7
|
-
env['rack.session'] = session
|
8
|
-
|
9
|
-
# TODO: in production we want to push the message to a queue and
|
10
|
-
# let the next available app instance pick it up, rather than
|
11
|
-
# the current instance to handle all traffic on this socket
|
12
|
-
|
13
|
-
context = Pakyow::CallContext.new(env)
|
14
|
-
context.process
|
15
|
-
res = context.finish
|
16
|
-
|
17
|
-
container = message['container']
|
18
|
-
partial = message['partial']
|
19
|
-
|
20
|
-
composer = context.presenter.composer
|
21
|
-
|
22
|
-
if container
|
23
|
-
body = composer.container(container.to_sym).includes(composer.partials).to_s
|
24
|
-
elsif partial
|
25
|
-
body = composer.partial(partial.to_sym).includes(composer.partials).to_s
|
26
|
-
else
|
27
|
-
body = res[2].body
|
28
|
-
end
|
29
|
-
|
30
|
-
response[:status] = res[0]
|
31
|
-
response[:headers] = res[1]
|
32
|
-
response[:body] = body.is_a?(StringIO) ? body.read : body
|
33
|
-
response
|
34
|
-
end
|