isomorfeus-transport 1.0.0.zeta25 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -21
  3. data/README.md +27 -36
  4. data/lib/isomorfeus/transport/client_processor.rb +35 -35
  5. data/lib/isomorfeus/transport/config.rb +182 -166
  6. data/lib/isomorfeus/transport/hamster_session_store.rb +96 -0
  7. data/lib/isomorfeus/transport/handler/authentication_handler.rb +70 -70
  8. data/lib/isomorfeus/transport/imports.rb +9 -0
  9. data/lib/isomorfeus/transport/middlewares.rb +13 -13
  10. data/lib/isomorfeus/transport/rack_middleware.rb +59 -55
  11. data/lib/isomorfeus/transport/request_agent.rb +34 -34
  12. data/lib/isomorfeus/transport/response_agent.rb +23 -23
  13. data/lib/isomorfeus/transport/server_processor.rb +129 -129
  14. data/lib/isomorfeus/transport/server_socket_processor.rb +54 -54
  15. data/lib/isomorfeus/transport/ssr_login.rb +28 -28
  16. data/lib/isomorfeus/transport/version.rb +5 -5
  17. data/lib/isomorfeus/transport/{websocket.rb → websocket_client.rb} +123 -123
  18. data/lib/isomorfeus/transport.rb +200 -196
  19. data/lib/isomorfeus-transport.rb +70 -61
  20. data/lib/lucid_authentication/mixin.rb +122 -122
  21. data/lib/lucid_channel/base.rb +8 -9
  22. data/lib/lucid_channel/mixin.rb +105 -105
  23. data/lib/lucid_handler/base.rb +8 -9
  24. data/lib/lucid_handler/mixin.rb +27 -27
  25. data/node_modules/.package-lock.json +27 -0
  26. data/node_modules/ws/LICENSE +19 -0
  27. data/node_modules/ws/README.md +496 -0
  28. data/node_modules/ws/browser.js +8 -0
  29. data/node_modules/ws/index.js +13 -0
  30. data/node_modules/ws/lib/buffer-util.js +126 -0
  31. data/node_modules/ws/lib/constants.js +12 -0
  32. data/node_modules/ws/lib/event-target.js +266 -0
  33. data/node_modules/ws/lib/extension.js +203 -0
  34. data/node_modules/ws/lib/limiter.js +55 -0
  35. data/node_modules/ws/lib/permessage-deflate.js +511 -0
  36. data/node_modules/ws/lib/receiver.js +612 -0
  37. data/node_modules/ws/lib/sender.js +414 -0
  38. data/node_modules/ws/lib/stream.js +180 -0
  39. data/node_modules/ws/lib/subprotocol.js +62 -0
  40. data/node_modules/ws/lib/validation.js +124 -0
  41. data/node_modules/ws/lib/websocket-server.js +485 -0
  42. data/node_modules/ws/lib/websocket.js +1144 -0
  43. data/node_modules/ws/package.json +61 -0
  44. data/node_modules/ws/wrapper.mjs +8 -0
  45. data/package.json +6 -0
  46. metadata +82 -46
  47. data/lib/isomorfeus/transport/dbm_session_store.rb +0 -51
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 650383d49c2b3d85ceab1ba50f081d83951393390a5a6cb2db9837e7261c8c70
4
- data.tar.gz: 8dc79b2037d59d5fc41e8f69fc0ac913f569abcb1e823f975fda3e37d2a358d1
3
+ metadata.gz: cd6bcb0fc97804f50a51cfb715eaeedac9e58a48924a1a141b1eeee961992699
4
+ data.tar.gz: 36cce06dd43f7cfd57c4b30623f5ac914e291e98e957ad6a39787bf3504b5052
5
5
  SHA512:
6
- metadata.gz: 5feea1467c33f7efa7452dedf08fe859f7daa90354e621750d82b9d99c33e63e0bc5b2651e0556f301dc0d7cd9ad8fbcae028503ae2d1bfb9d620c60f8574802
7
- data.tar.gz: d7582e45abab5eeaffebfca8473ed0ca74664faddd57be5e21cff0d484713a221a30ae07c55c2b9f1230acf9030e847628218fe8b060d7d9e8cc243111f25eae
6
+ metadata.gz: fb5c37666f091a021b5b167c317132eb3bf300c9fef46f3f42260c3a8d635d63ccf18ca3c2284fb484db8c4b90a3ca1ff1d93ddc63945a2de34ff586eb42a47e
7
+ data.tar.gz: 59c4b3927030fdfcf9383bd6296c4c4709b4425d875f26a8170d37f575be3622162e4a46c01c92d20ccf8f392542e56a5c25c95dcbea9b4b0ec15640ee2a8932
data/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2018, 2019 Jan Biedermann
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, 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,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2018, 2019 Jan Biedermann
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,36 +1,27 @@
1
- # isomorfeus-transport
2
-
3
- Transport and PubSub for Isomorfeus.
4
-
5
- ### Community and Support
6
- At the [Isomorfeus Framework Project](http://isomorfeus.com)
7
-
8
- ## Installation
9
- isomorfeus-transport is usually installed with the installer.
10
- Otherwise add to your Gemfile:
11
- ```ruby
12
- gem 'isomorfeus-transport'
13
- ```
14
- and bundle install/update
15
-
16
- ## Server Side Rendering
17
- `yarn add ws`
18
-
19
- The 'ws' module then needs to be imported in application_ssr.js:
20
- ```
21
- import WebSocket from 'ws';
22
- global.WebSocket = WebSocket;
23
- ```
24
-
25
- ## Configuration options
26
-
27
- Client and Server:
28
- - Isomorfeus.api_websocket_path - path for server side endpoint, default: `/isomorfeus/api/websocket`
29
-
30
- Server only:
31
- - Isomorfeus.middlewares - all the rack middlewares to load
32
-
33
- ## Usage
34
-
35
- - [Authentication and Current User](https://github.com/isomorfeus/isomorfeus-project/blob/master/ruby/isomorfeus-transport/docs/authentication.md)
36
- - [Channels (PubSub)](https://github.com/isomorfeus/isomorfeus-project/blob/master/ruby/isomorfeus-transport/docs/channels.md)
1
+ # isomorfeus-transport
2
+
3
+ Transport and PubSub for Isomorfeus.
4
+
5
+ ### Community and Support
6
+ At the [Isomorfeus Framework Project](http://isomorfeus.com)
7
+
8
+ ## Installation
9
+ isomorfeus-transport is usually installed with the installer.
10
+ Otherwise add to your Gemfile:
11
+ ```ruby
12
+ gem 'isomorfeus-transport'
13
+ ```
14
+ and bundle install/update
15
+
16
+ ## Configuration options
17
+
18
+ Client and Server:
19
+ - Isomorfeus.api_websocket_path - path for server side endpoint, default: `/isomorfeus/api/websocket`
20
+
21
+ Server only:
22
+ - Isomorfeus.middlewares - all the rack middlewares to load
23
+
24
+ ## Usage
25
+
26
+ - [Authentication and Current User](https://github.com/isomorfeus/isomorfeus-project/blob/master/ruby/isomorfeus-transport/docs/authentication.md)
27
+ - [Channels (PubSub)](https://github.com/isomorfeus/isomorfeus-project/blob/master/ruby/isomorfeus-transport/docs/channels.md)
@@ -1,35 +1,35 @@
1
- module Isomorfeus
2
- module Transport
3
- class ClientProcessor
4
- def self.process(json_hash)
5
- if json_hash.key?(:response)
6
- process_response(json_hash)
7
- elsif json_hash.key?(:notification)
8
- process_message(json_hash)
9
- end
10
- end
11
-
12
- def self.process_message(message_hash)
13
- processor_class_name = message_hash[:notification][:class]
14
- Isomorfeus.raise_error(message: "Not a valid channel class #{processor_class_name}!") unless Isomorfeus.valid_channel_class_name?(processor_class_name)
15
- processor_class = Isomorfeus.cached_channel_class(processor_class_name)
16
- unless processor_class.respond_to?(:process_message)
17
- Isomorfeus.raise_error(message: "Cannot process message, #{processor_class} must be a Channel and must have the on_message block defined!")
18
- end
19
- processor_class.process_message(message_hash[:notification][:message], message_hash[:notification][:error], message_hash[:notification][:channel])
20
- end
21
-
22
- def self.process_response(response_hash)
23
- response_hash[:response][:agent_ids].keys.each do |agent_id|
24
- agent = Isomorfeus::Transport::RequestAgent.get!(agent_id)
25
- Isomorfeus::Transport.unregister_request_in_progress(agent_id)
26
- unless agent.promise.realized?
27
- agent.full_response = response_hash
28
- agent.response = response_hash[:response][:agent_ids][agent_id]
29
- agent.promise.resolve(agent)
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
1
+ module Isomorfeus
2
+ module Transport
3
+ class ClientProcessor
4
+ def self.process(json_hash)
5
+ if json_hash.key?(:response)
6
+ process_response(json_hash)
7
+ elsif json_hash.key?(:notification)
8
+ process_message(json_hash)
9
+ end
10
+ end
11
+
12
+ def self.process_message(message_hash)
13
+ processor_class_name = message_hash[:notification][:class]
14
+ Isomorfeus.raise_error(message: "Not a valid channel class #{processor_class_name}!") unless Isomorfeus.valid_channel_class_name?(processor_class_name)
15
+ processor_class = Isomorfeus.cached_channel_class(processor_class_name)
16
+ unless processor_class.respond_to?(:process_message)
17
+ Isomorfeus.raise_error(message: "Cannot process message, #{processor_class} must be a Channel and must have the on_message block defined!")
18
+ end
19
+ processor_class.process_message(message_hash[:notification][:message], message_hash[:notification][:error], message_hash[:notification][:channel])
20
+ end
21
+
22
+ def self.process_response(response_hash)
23
+ response_hash[:response][:agent_ids].keys.each do |agent_id|
24
+ agent = Isomorfeus::Transport::RequestAgent.get!(agent_id)
25
+ Isomorfeus::Transport.unregister_request_in_progress(agent_id)
26
+ unless agent.promise.realized?
27
+ agent.full_response = response_hash
28
+ agent.response = response_hash[:response][:agent_ids][agent_id]
29
+ agent.promise.resolve(agent)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,166 +1,182 @@
1
- module Isomorfeus
2
- # available settings
3
- class << self
4
- def cached_channel_classes
5
- @cached_channel_classes ||= {}
6
- end
7
-
8
- def cached_channel_class(class_name)
9
- return "::#{class_name}".constantize if Isomorfeus.development?
10
- return cached_channel_classes[class_name] if cached_channel_classes.key?(class_name)
11
- cached_channel_classes[class_name] = "::#{class_name}".constantize
12
- end
13
-
14
- def valid_channel_class_names
15
- @valid_channel_class_names ||= Set.new
16
- end
17
-
18
- def add_valid_channel_class(klass)
19
- valid_channel_class_names << raw_class_name(klass)
20
- end
21
-
22
- def raw_class_name(klass)
23
- class_name = klass.name
24
- class_name = class_name.split('>::').last if class_name.start_with?('#<')
25
- class_name
26
- end
27
- end
28
-
29
- if RUBY_ENGINE == 'opal'
30
- add_client_option(:api_websocket_path)
31
- add_client_option(:cookie_eater_path)
32
- add_client_option(:transport_init_class_names, [])
33
-
34
- class << self
35
- def valid_channel_class_name?(class_name)
36
- cached_channel_class(class_name) # because of autoloader
37
- valid_channel_class_names.include?(class_name)
38
- end
39
-
40
- def add_transport_init_class_name(init_class_name)
41
- transport_init_class_names << init_class_name
42
- end
43
-
44
- def current_user
45
- @current_user ||= init_current_user
46
- end
47
-
48
- def init_current_user
49
- if Isomorfeus.current_user_sid
50
- Isomorfeus.instance_from_sid(Isomorfeus.current_user_sid)
51
- else
52
- Anonymous.new
53
- end
54
- end
55
-
56
- def set_current_user(user)
57
- if user
58
- @current_user = user
59
- Isomorfeus.current_user_sid = user.to_sid
60
- else
61
- @current_user = Anonymous.new
62
- end
63
- end
64
- end
65
- else
66
- class << self
67
- attr_accessor :api_websocket_path
68
- attr_accessor :cookie_eater_path
69
- attr_accessor :session_store
70
- attr_accessor :cookie_dbm_path
71
-
72
- def valid_channel_class_name?(class_name)
73
- valid_channel_class_names.include?(class_name)
74
- end
75
-
76
- def add_middleware(middleware)
77
- Isomorfeus.middlewares << middleware
78
- end
79
-
80
- def insert_middleware_after(existing_middleware, new_middleware)
81
- index_of_existing = Isomorfeus.middlewares.index(existing_middleware)
82
- unless Isomorfeus.middlewares.include?(new_middleware)
83
- if index_of_existing
84
- Isomorfeus.middlewares.insert(index_of_existing + 1, new_middleware)
85
- else
86
- Isomorfeus.middlewares << new_middleware
87
- end
88
- end
89
- end
90
-
91
- def insert_middleware_before(existing_middleware, new_middleware)
92
- index_of_existing = Isomorfeus.middlewares.index(existing_middleware)
93
- unless Isomorfeus.middlewares.include?(new_middleware)
94
- if index_of_existing
95
- Isomorfeus.middlewares.insert(index_of_existing, new_middleware)
96
- else
97
- Isomorfeus.middlewares << new_middleware
98
- end
99
- end
100
- end
101
-
102
- def middlewares
103
- @middlewares ||= Set.new
104
- end
105
-
106
- def valid_handler_class_names
107
- @valid_handler_class_names ||= Set.new
108
- end
109
-
110
- def valid_handler_class_name?(class_name)
111
- valid_handler_class_names.include?(class_name)
112
- end
113
-
114
- def add_valid_handler_class(klass)
115
- valid_handler_class_names << raw_class_name(klass)
116
- end
117
-
118
- def cached_handler_classes
119
- @cached_handler_classes ||= {}
120
- end
121
-
122
- def cached_handler_class(class_name)
123
- return "::#{class_name}".constantize if Isomorfeus.development?
124
- return cached_handler_classes[class_name] if cached_handler_classes.key?(class_name)
125
- cached_handler_classes[class_name] = "::#{class_name}".constantize
126
- end
127
-
128
- def valid_user_class_names
129
- @valid_user_class_names ||= Set.new
130
- end
131
-
132
- def valid_user_class_name?(class_name)
133
- valid_user_class_names.include?(class_name)
134
- end
135
-
136
- def add_valid_user_class(klass)
137
- valid_user_class_names << raw_class_name(klass)
138
- end
139
-
140
- def cached_user_classes
141
- @cached_user_classes ||= {}
142
- end
143
-
144
- def cached_user_class(class_name)
145
- return "::#{class_name}".constantize if Isomorfeus.development?
146
- return cached_user_classes[class_name] if cached_user_classes.key?(class_name)
147
- cached_user_classes[class_name] = "::#{class_name}".constantize
148
- end
149
-
150
- def current_user
151
- Thread.current[:isomorfeus_user]
152
- end
153
-
154
- def pub_sub_client
155
- Thread.current[:isomorfeus_pub_sub_client]
156
- end
157
- end
158
-
159
- self.cookie_dbm_path = 'cookie'
160
- self.session_store = Isomorfeus::Transport::DbmSessionStore.new # dont use this one, but we keep it here to have at least something
161
- end
162
-
163
- # defaults
164
- self.api_websocket_path = '/isomorfeus/api/websocket'
165
- self.cookie_eater_path = '/isomorfeus/cookie/eat'
166
- end
1
+ module Isomorfeus
2
+ # available settings
3
+ class << self
4
+ def cached_channel_classes
5
+ @cached_channel_classes ||= {}
6
+ end
7
+
8
+ def cached_channel_class(class_name)
9
+ return "::#{class_name}".constantize if Isomorfeus.development?
10
+ return cached_channel_classes[class_name] if cached_channel_classes.key?(class_name)
11
+ cached_channel_classes[class_name] = "::#{class_name}".constantize
12
+ end
13
+
14
+ def valid_channel_class_names
15
+ @valid_channel_class_names ||= Set.new
16
+ end
17
+
18
+ def add_valid_channel_class(klass)
19
+ valid_channel_class_names << raw_class_name(klass)
20
+ end
21
+
22
+ def raw_class_name(klass)
23
+ class_name = klass.name
24
+ class_name = class_name.split('>::').last if class_name.start_with?('#<')
25
+ class_name
26
+ end
27
+ end
28
+
29
+ if RUBY_ENGINE == 'opal'
30
+ add_client_option(:api_websocket_host)
31
+ add_client_option(:api_websocket_port)
32
+ add_client_option(:api_websocket_path)
33
+ add_client_option(:cookie_eater_path)
34
+ add_client_option(:transport_init_class_names, [])
35
+
36
+ class << self
37
+ def valid_channel_class_name?(class_name)
38
+ cached_channel_class(class_name) # because of autoloader
39
+ valid_channel_class_names.include?(class_name)
40
+ end
41
+
42
+ def add_transport_init_class_name(init_class_name)
43
+ transport_init_class_names << init_class_name
44
+ end
45
+
46
+ def current_user
47
+ @current_user ||= init_current_user
48
+ end
49
+
50
+ def init_current_user
51
+ if Isomorfeus.current_user_sid
52
+ Isomorfeus.instance_from_sid(Isomorfeus.current_user_sid)
53
+ else
54
+ Anonymous.new
55
+ end
56
+ end
57
+
58
+ def set_current_user(user)
59
+ if user
60
+ @current_user = user
61
+ Isomorfeus.current_user_sid = user.sid
62
+ else
63
+ @current_user = Anonymous.new
64
+ end
65
+ end
66
+ end
67
+ else
68
+ class << self
69
+ attr_accessor :api_websocket_host
70
+ attr_accessor :api_websocket_port
71
+ attr_accessor :api_websocket_path
72
+ attr_accessor :cookie_eater_path
73
+ attr_reader :session_store
74
+
75
+ def valid_channel_class_name?(class_name)
76
+ valid_channel_class_names.include?(class_name)
77
+ end
78
+
79
+ def add_middleware(middleware)
80
+ Isomorfeus.middlewares << middleware
81
+ end
82
+
83
+ def insert_middleware_after(existing_middleware, new_middleware)
84
+ index_of_existing = Isomorfeus.middlewares.index(existing_middleware)
85
+ unless Isomorfeus.middlewares.include?(new_middleware)
86
+ if index_of_existing
87
+ Isomorfeus.middlewares.insert(index_of_existing + 1, new_middleware)
88
+ else
89
+ Isomorfeus.middlewares << new_middleware
90
+ end
91
+ end
92
+ end
93
+
94
+ def insert_middleware_before(existing_middleware, new_middleware)
95
+ index_of_existing = Isomorfeus.middlewares.index(existing_middleware)
96
+ unless Isomorfeus.middlewares.include?(new_middleware)
97
+ if index_of_existing
98
+ Isomorfeus.middlewares.insert(index_of_existing, new_middleware)
99
+ else
100
+ Isomorfeus.middlewares << new_middleware
101
+ end
102
+ end
103
+ end
104
+
105
+ def middlewares
106
+ @middlewares ||= Set.new
107
+ end
108
+
109
+ def valid_handler_class_names
110
+ @valid_handler_class_names ||= Set.new
111
+ end
112
+
113
+ def valid_handler_class_name?(class_name)
114
+ valid_handler_class_names.include?(class_name)
115
+ end
116
+
117
+ def add_valid_handler_class(klass)
118
+ valid_handler_class_names << raw_class_name(klass)
119
+ end
120
+
121
+ def cached_handler_classes
122
+ @cached_handler_classes ||= {}
123
+ end
124
+
125
+ def cached_handler_class(class_name)
126
+ return "::#{class_name}".constantize if Isomorfeus.development?
127
+ return cached_handler_classes[class_name] if cached_handler_classes.key?(class_name)
128
+ cached_handler_classes[class_name] = "::#{class_name}".constantize
129
+ end
130
+
131
+ def valid_user_class_names
132
+ @valid_user_class_names ||= Set.new
133
+ end
134
+
135
+ def valid_user_class_name?(class_name)
136
+ valid_user_class_names.include?(class_name)
137
+ end
138
+
139
+ def add_valid_user_class(klass)
140
+ valid_user_class_names << raw_class_name(klass)
141
+ end
142
+
143
+ def cached_user_classes
144
+ @cached_user_classes ||= {}
145
+ end
146
+
147
+ def cached_user_class(class_name)
148
+ return "::#{class_name}".constantize if Isomorfeus.development?
149
+ return cached_user_classes[class_name] if cached_user_classes.key?(class_name)
150
+ cached_user_classes[class_name] = "::#{class_name}".constantize
151
+ end
152
+
153
+ def current_user
154
+ Thread.current[:isomorfeus_user]
155
+ end
156
+
157
+ def pub_sub_client
158
+ Thread.current[:isomorfeus_pub_sub_client]
159
+ end
160
+
161
+ def session_store
162
+ @session_store ||= @session_store_init.call
163
+ end
164
+
165
+ def session_store_init(&block)
166
+ @session_store_init = block
167
+ end
168
+ end
169
+
170
+ self.session_store_init do
171
+ store_path = File.expand_path(File.join(Isomorfeus.root, 'data', Isomorfeus.env), 'session_store')
172
+ Isomorfeus::Transport::HamsterSessionStore.new(store_path) # dont use this one, but we keep it here to have at least something
173
+ end
174
+ end
175
+
176
+ # defaults
177
+ self.api_websocket_host = 'localhost'
178
+ self.api_websocket_port = '5000'
179
+ self.api_websocket_path = '/isomorfeus/api/websocket'
180
+
181
+ self.cookie_eater_path = '/isomorfeus/cookie/eat'
182
+ end
@@ -0,0 +1,96 @@
1
+ module Isomorfeus
2
+ module Transport
3
+ class HamsterSessionStore
4
+ class << self
5
+ def environment
6
+ @environment
7
+ end
8
+
9
+ def environment=(env)
10
+ @environment = env
11
+ end
12
+
13
+ def ref
14
+ @ref ||= 0
15
+ end
16
+
17
+ def ref=(val)
18
+ @ref = val
19
+ end
20
+
21
+ def refa
22
+ self.ref += 1
23
+ end
24
+
25
+ def refs
26
+ self.ref -= 1 if self.ref > 0
27
+ end
28
+
29
+ def finalize(cls)
30
+ proc do
31
+ cls.refs
32
+ if cls.ref == 0
33
+ cls.environment.close rescue nil
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ def initialize(cookie_hamster_path)
40
+ @cookie_hamster_path = cookie_hamster_path
41
+ open_environment
42
+ @db = self.class.environment.database('cookies', create: true)
43
+ ObjectSpace.define_finalizer(self, self.class.finalize(self.class))
44
+ end
45
+
46
+ def add(session_id:, cookie:, user:, accessor:)
47
+ @db.env.transaction do
48
+ @db.put(session_id, Oj.dump([user.class.to_s, user.key], mode: :strict))
49
+ @db.put(accessor, cookie)
50
+ end
51
+ end
52
+
53
+ def take_cookie(accessor:)
54
+ @db.env.transaction do
55
+ cookie = @db.get(accessor)
56
+ if cookie
57
+ session_info = cookie.split('; ').first
58
+ session_id = session_info.split('=').last.strip
59
+ @db.put("eaten_#{accessor}", session_id)
60
+ @db.delete(accessor)
61
+ else
62
+ # asked for the same cookie a second time
63
+ # can probably only be due to session hijacking
64
+ # so delete all sessions associated with that accessor
65
+ session_id = @db.get("eaten_#{accessor}")
66
+ @db.delete(session_id) if session_id
67
+ end
68
+ cookie
69
+ end
70
+ end
71
+
72
+ def get_user(session_id:)
73
+ json = @db.get(session_id)
74
+ if json
75
+ user_info = Oj.load(json, mode: :strict)
76
+ user_info[0].constantize.load(key: user_info[1]) if user_info
77
+ end
78
+ end
79
+
80
+ def remove(session_id:)
81
+ @db.env.transaction do
82
+ @db.delete(session_id)
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def open_environment
89
+ return self.class.refa if self.class.environment
90
+ FileUtils.mkdir_p(@cookie_hamster_path) unless Dir.exist?(@cookie_hamster_path)
91
+ self.class.environment = Isomorfeus::Hamster.new(@cookie_hamster_path)
92
+ self.class.refa
93
+ end
94
+ end
95
+ end
96
+ end